library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(ggplot2)
library(forcats)
library(here)
here() starts at /Users/avrilwang/Desktop/Project-Plasmodium
library(deSolve)
library(crone)
library(optimParallel)
Loading required package: parallel
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(doRNG)
Loading required package: rngtools
library(arrow)

Attaching package: ‘arrow’

The following object is masked from ‘package:utils’:

    timestamp
library(stringr)
library(parallel)
library(ggpubr)
library(scales)

Notebook for plotting all of the figures for PloS Biology manuscript submission

Guidelines: taken from https://journals.plos.org/plosbiology/s/figures#loc-figure-file-requirements 1. format: eps 2. max file size: 10 MB 3. text size: Arial, Times, or Symbol font only in 8-12 point 2. figure size: Width: 789 – 2250 pixels (at 300 dpi). Height maximum: 2625 pixels (at 300 dpi).

#=========================================# figure 1: best single and co-infection cue #=========================================# Figure displaying the reaction norms of best single and co-infection.

#——- optimal cue reaction norm ———–# # read data

process data for reaction norm

# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))

# get si_label with ci cue range
si_ci_rug.df <- ci_rug.df %>% 
  mutate(label_si = case_when(
    label %in% c("I", "I1+I2") ~ "I",
    label %in% c("I log","I1+I2 log") ~ "I log",
    label %in% c("Ig", "Ig1+Ig2") ~ "Ig",
    label %in% c("Ig log") ~ "Ig log",
    label %in% c("sum", "I+Ig") ~ "I+Ig",
    label %in% c("sum log", "I+Ig log") ~ "I+Ig log",
    label == "R" ~ "R",
    label == "R log" ~ "R log",
    label %in% c("G", "G1+G2") ~ "G",
    label == "G log" ~ "G log"
  )) 

# get limit for si_rug
si_rug_lim.df <- si_rug.df %>% 
  filter(time <= 20) %>%
  group_by(label)%>% 
  summarise(min = min(value, na.rm = T)*0.9,
         max = max(value, na.rm = T)*1.1) %>% 
  select(label_si = label, min_si = min, max_si = max)

# filter to restriction conversion rate reaction norm range to cue ranges that appear in rug
## change to Inf/-inf to NA. Note that I am first joining with si rug lim to check which limit is larger, We will go with the cue range that has the largest span
ci_rug_lim.df <- si_ci_rug.df %>% 
  group_by(label) %>% 
  mutate(min = min(value, na.rm = T)*0.9,
         max = max(value, na.rm = T)*1.1) %>% 
  distinct(label, .keep_all = T) %>% 
  select(label, label_si, min, max)

rug_lim.final <- ci_rug_lim.df %>% left_join(si_rug_lim.df, by = "label_si") %>% 
  mutate(final_min = min(min, min_si),
         final_max = max(max, max_si))

# get second rug_lim.final for single infection
rug_lim.final2 <- rug_lim.final %>% 
  group_by(label_si) %>% 
  mutate(final_min = min(final_min, na.rm = T),
         final_max = max(final_max, na.rm = T))

# filter ci_rn by limit
ci_rn.df2 <- ci_rn.df %>% 
  left_join(rug_lim.final, by  = "label") %>% 
  group_by(label) %>% 
  filter(cue_range <= final_max & cue_range >= final_min) %>% 
  arrange(cue_range, .by_group = T) %>% 
  filter(row_number() %% 10 == 0) 
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))

match single infection rn with coinfection

# get ci label to si rug and filter by limit
si_rn.df2 <- left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c("label" = "label_si")) %>% 
  left_join(rug_lim.final, by  = c("label_ci" = "label")) %>% 
  group_by(label_ci) %>% 
  filter(cue_range <= final_max & cue_range >= final_min) %>% 
  arrange(cue_range, .by_group = T) %>% 
  filter(row_number() %% 10 == 0) %>% 
  select(cue_range, cr, label_ci, label_si)
Warning in left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c(label = "label_si")) :
  Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 1 of `x` matches multiple rows in `y`.
ℹ Row 1 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# get ci label to si rug, we will keep one unique value per label
si_rug.df2 <- select(si_rug.df, value, label_si = label) %>% distinct(value, label_si)

plot reaction norm

# join with ezlabel
ci_rn.df3 <- ci_rn.df2 %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rn.df3 <- si_rn.df2 %>% left_join(ez_label, by = "label_ci")
ci_rug.df3 <- ci_rug.df %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rug.df3 <- si_rug.df2 %>% left_join(ez_label, by = "label_si")
Warning in left_join(., ez_label, by = "label_si") :
  Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 27002 of `x` matches multiple rows in `y`.
ℹ Row 12 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# redo order of cues
ci_rn.df3$ez_label <- factor(ci_rn.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10")) 

si_rn.df3$ez_label <- factor(si_rn.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))

ci_rug.df3$ez_label <- factor(ci_rug.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))

si_rug.df3$ez_label <- factor(si_rug.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))
# plot
ggplot() +
  geom_line(data = ci_rn.df3, aes(x = cue_range, y = cr, color = "Co-infection")) +
  geom_point(data = ci_rn.df3 %>% 
    group_by(label) %>% 
    mutate(ten_th = round(n()/10)) %>% 
    filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Co-infection", shape = "Co-infection"), size = 2) +
  geom_line(data = si_rn.df3, aes(x = cue_range, y = cr, color = "Single infection")) +
  geom_point(data = si_rn.df3 %>% 
    group_by(label_ci) %>% 
    mutate(ten_th = round(n()/10)) %>% 
    filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Single infection", shape = "Single infection"), size = 2) +
  geom_rug(data = ci_rug.df3, aes(x = value), color = "#4575b4", sides = "t", length = unit(0.1, "npc")) +
  geom_rug(data = si_rug.df3, aes(x = value), color = "#fc8d59", sides = "b", length = unit(0.1, "npc")) +
  facet_wrap(~ez_label, scales = "free_x", ncol = 2) +
  ylim(-0.3, 1.3) +
  theme_bw() +
  labs(y = "Conversion rate", x = "Cue range", color = "Model", shape = "Model") +
  scale_x_continuous(labels = function(x) format(x, scientific = T),
                     guide = guide_axis(check.overlap = TRUE)) + 
                    theme(axis.text.x = element_text(size = 7),
                          legend.position = "right")  +
  scale_color_manual(values=c( "#4575b4", "#fc8d59")) +
  theme(strip.text.x = element_text(margin = margin(b = 0.5, t = 0.5)))

ggsave(units = "px", dpi = 300, width = 2000, height = 2500, filename = here("figures/plos-bio/reaction_norm.tiff"), bg = "white", scale = 1.1)

#=========================================# Plotting single and co-infection fitness scatter plot #=========================================# # import in data

# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet")) 

# co-infection dynamics
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))

ez_label <- read.csv(here("data/ez_label.csv"))

process for final 20 days fitness

# get single infection maximum tau_cum for 20 days
si_fitness.df <- si_dyn.df %>% 
  filter(variable == "tau_cum" & time == 20)

# get co-infection maximum tau_cum for 20 days
ci_fitness.df <- ci_dyn.df %>% 
  filter(variable == "tau_cum1" & time == 20)

# join together two dataframes and add labels
si_ci_fitness.df <- select(ci_fitness.df, fitness_ci = value, label_ci = label) %>% 
  left_join(ez_label, by = "label_ci") %>% 
  left_join(select(si_fitness.df, fitness_si = value, id_si = id), by = "id_si") %>% 
  select(ez_label_si, ez_label, fitness_si, fitness_ci) %>% 
  rbind(data.frame( # add time
    ez_label_si = "Time", 
    ez_label = "Time",
    fitness_si =  9.787899,
    fitness_ci  = 2.311841
  ))

si_ci_fitness.df
# join together two dataframes and add labels
si_ci_fitness.df <- select(ci_fitness.df, fitness_ci = value, label_ci = label) %>% 
  left_join(ez_label, by = "label_ci") %>% 
  left_join(select(si_fitness.df, fitness_si = value, id_si = id), by = "id_si") %>% 
  select(ez_label_si, ez_label, fitness_si, fitness_ci) %>% 
  rbind(data.frame( # add time
    ez_label_si = "Time", 
    ez_label = "Time",
    fitness_si =  9.787899,
    fitness_ci  = 2.311841
  ))

plot scatter point of single infection vs co-infection

si_ci_fitness.pl <- ggplot() +
  geom_point(data = si_ci_fitness.df, aes(x = fitness_si, y = fitness_ci, color = ez_label_si, shape = ez_label_si), size = 3.5) +
  ggrepel::geom_label_repel(data = si_ci_fitness.df, aes(label = ez_label, x = fitness_si, y = fitness_ci),
                            fill = "white",xlim = c(-Inf, Inf), ylim = c(NA, NA)) +
  labs(x = "Maximum single infection fitness", y = "Maximum Co-infection fitness (per strain)",
       color = "Single infection cue", shape = "Single infection cue") +
  scale_shape_manual(values = 15:25) +
  lims(x = c(8, 10.3)) +
  theme_bw()

#=========================================================# # time series conversion rate for single and co-infection #=========================================================# #———get “ideal” single infection and co-infection dynamics———# This is when stuff are optimized based on time

source(here("functions/chabaudi_si_clean.R"))
source(here("functions/chabaudi_ci_clean.R"))

# single infection dynamic with time as cue. Optimized using local optimizer. Note that the time variable in dual cue is slightly different with higher flexibility. While that increases the fitness value by ~0.1, the overall conversion rate dynamic does not change that much
si_t.df <- chabaudi_si_clean(
  parameters_cr = c(4.55386, -13.0056, 4.15466, -11.9424),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, 20, by = 1e-3),
  cue = "t",
  solver = "vode",
  dyn = T)

# co-infection dynamic with time as cue
ci_t.df <- chabaudi_ci_clean(parameters_cr_1 = c(26.16425,  -71.07799,  53.34121,   -166.25693),
                            parameters_cr_2 = c(26.16425,   -71.07799,  53.34121,   -166.25693),
                            immunity = "tsukushi",
                            parameters = parameters_tsukushi,
                            time_range = time_range, 
                            cue_1 =  "t",
                            cue_2= "t",
                            cue_range_1 = time_range, # cue range of strain 1
                            cue_range_2 = time_range, # cue range of strain 2
                            log_cue_1 = "none", # whether to log transform cue 1
                            log_cue_2 = "none", # whether to log transform cue 2
                            solver = "vode", # solver for numerical integration. Vode often gives faster runs
                              dyn = T)

# get only conversion rate and make same format as si_cr.df2/ci_cr.df2
si_t.df %>% filter(time == 20 & variable == "tau_cum") ## fitness value of time as cue in single infection
si_t.cr <- si_t.df %>% 
  filter(variable == "cr") %>% 
  mutate(ez_label_si = "Time", 
         fitness_si =9.787899) %>% 
  select(time, value, fitness_si, ez_label_si)


## get fitness value of co-infection time
ci_t.df %>% filter(variable == "tau_cum1") %>% summarize(max = max(value, na.rm = T))
ci_t.cr <- ci_t.df %>% 
  filter(variable == "cr_1") %>% 
  mutate(ez_label = "Time", 
         fitness_ci = 2.311841) %>%
  select(time, value, fitness_ci, ez_label)

#——— single infection conversion rate heat map————–# # process info for single infection

—————–co-infection conversion rate heatmap———–

plot co-infeciton convesion rate heatmap

ggplot() +
  geom_raster(data = ci_cr.df2, 
              aes(x = time, y = forcats::fct_reorder(ez_label, fitness_ci), fill = value)) +
  labs(x = "Time (days)", y = "Co-infection cues", fill = "Conversion rate") +
  viridis::scale_fill_viridis(limits = c(0, 1), , oob = scales::squish) +
  xlim(1, 20) +
  theme_bw()
Warning: Removed 17028 rows containing missing values (`geom_raster()`).

#——— assemble final figure ————–#

# combine conversion rate dynamic of single infection and co-infection
cr.pl <- ggarrange(si_cr.pl, ci_cr.pl, labels = c("B", "C"), ncol = 2, common.legend = T, align = "h")

# combine with fitness scatterplot
ggarrange(si_ci_fitness.pl, cr.pl, ncol = 1, labels = c("A", ""), align = "hv")

# save
ggsave(units = "px", dpi = 300, width = 2000, height = 2000, filename = here("figures/plos-bio/fitness_cr-dyn.tiff"), bg = "white", scale = 1.35)

#===========================================================# # Demographic stochasticity #===========================================================# #———- plot heat map—————# # import in all fitness files

file_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv", full.names = T)
name_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv")
name_ls <- gsub("*.csv", "", name_ls)

# 60, which is about right
length(file_ls)
[1] 60
# read in files
fitness.ls <- lapply(file_ls, read.csv)
Warning: stack imbalance in 'lapply', 6 then 8
Warning: stack imbalance in '<-', 2 then 4
# assign unique ID
fitness.ls <- mapply(cbind, fitness.ls, "ID" = name_ls, SIMPLIFY = F)

process data

# get metainfo from ID
fitness.ls2 <- mclapply(fitness.ls, function(x){
  id_col <- x$ID
  # string split to extract all info
  cue <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
  log <- unlist(str_split(unique(id_col), pattern = "_"))[[4]]
  rand_var <- unlist(str_split(unique(id_col), pattern = "_"))[[5]]
  
  # get mean
  mean_fitness <- mean(x$max_fitness)
  # get sd
  sd_fitness <- sd(x$max_fitness)
  
  # bind results
  res <- cbind(x, cue= cue, log = log, rand_var = rand_var, mean_fitness = mean_fitness, sd_fitness = sd_fitness)
  return(res)
})

Get reference data

reference_ls <- list.files(path = here("data/MC2"), pattern = "*.csv", full.names = T)
reference_name.ls <- gsub("*.csv", "", list.files(path = here("data/MC2/"), pattern = "*.csv"))

# read in the files
reference.ls <- lapply(reference_ls, read.csv)

# assign unique ID
reference.ls <- mapply(cbind, reference.ls, "ID" = reference_name.ls, SIMPLIFY = F)

# get meta data
reference.ls2 <- mclapply(reference.ls, function(x){
  id_col <- x$ID
  # string split to extract all info
  cue <- unlist(str_split(unique(id_col), pattern = "_"))[[2]]
  # get log
  third_col <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
  log <- ifelse(third_col == "log", "log10", "none")
  
  # get mean
  mean_fitness <- mean(x$max_fitness)
  
  # get sd
  sd_fitness <- sd(x$max_fitness)
  
  # bind results
  res <- cbind(x, cue= cue, log = log, rand_var = "all", ref_mean_fitness = mean_fitness, ref_sd_fitness = sd_fitness)
  return(res)
})

combine MC partitioned and reference df

# get unique column values for each cue, log, and rand_var combo
fitness.ls3 <- do.call(rbind, fitness.ls2)
fitness.ls3 <- fitness.ls3 %>% dplyr::distinct(ID, .keep_all = T)

# repeat with reference
reference.ls3 <- do.call(rbind, reference.ls2)
reference.ls3 <- reference.ls3 %>% dplyr::distinct(ID, .keep_all = T)

# combine!
ref_fit.df <- left_join(fitness.ls3, reference.ls3, by = c("cue" = "cue", "log"= "log"))

compute proportion fitness and variation

ref_fit.df2 <- ref_fit.df %>% 
  mutate(p_sd = sd_fitness/ref_sd_fitness,
         p_mean = ref_mean_fitness/mean_fitness,
         cue_log = paste0(cue, "_", log),
         label = case_when(
           cue == "G" ~ "Gametocyte",
           cue == "I" ~ "Asexual iRBC",
           cue == "I+Ig" ~ "Asexual&sexual\niRBC",
           cue == "Ig" ~ "Sexual iRBC",
           cue == "R" ~ "RBC"
           ),
         parameter = case_when(
           rand_var.x == "rho" ~ "ρ",
           rand_var.x == "phin" ~ "ϕn",
           rand_var.x == "phiw"~ "ϕw",
           rand_var.x == "psin" ~ "ψn",
           rand_var.x == "psiw" ~ "ψw",
           rand_var.x == "beta" ~ "β"
         ))

plot!

# variation
mc_b <- ggplot() +
  geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_sd)) +
  facet_wrap(~log) +
  theme_bw() +
  viridis::scale_fill_viridis() +
  labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(sd("1 parameter randomized"), sd("all parameters randomized")))) +
  theme(legend.position="top",
        axis.text.x = element_text(angle = 45, hjust=1))

# mean fitness
mc_c <- ggplot() +
  geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_mean)) +
  facet_wrap(~log) +
  theme_bw() +
  viridis::scale_fill_viridis() +
  labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(Mean("all parameters randomized"), Mean("1 parameter randomized")))) +
  theme(legend.position="top",
        axis.text.x = element_text(angle = 45, hjust=1))

mc_partition <- ggarrange(mc_b, mc_c, ncol = 1)

#————– get violine plot of variation in fitness ——————–# # read MC data

# read in dymamics
mc_G_log.dyn <- read_parquet(here("data/MC2/mc_G_log_dyn.parquet"))
mc_G.dyn <- read_parquet(here("data/MC2/mc_G_dyn.parquet"))
mc_R_log.dyn <- read_parquet(here("data/MC2/mc_R_log_dyn.parquet"))
mc_R.dyn <- read_parquet(here("data/MC2/mc_R_dyn.parquet"))
mc_I_log.dyn <- read_parquet(here("data/MC2/mc_I_log_dyn.parquet"))
mc_I.dyn <- read_parquet(here("data/MC2/mc_I_dyn.parquet"))
mc_Ig_log.dyn <- read_parquet(here("data/MC2/mc_Ig_log_dyn.parquet"))
mc_Ig.dyn <- read_parquet(here("data/MC2/mc_Ig_dyn.parquet"))
mc_I_Ig_log.dyn <- read_parquet(here("data/MC2/mc_I+Ig_log_dyn.parquet"))
mc_I_Ig.dyn <- read_parquet(here("data/MC2/mc_I+Ig_dyn.parquet"))

# read in fitness
mc_G_log.fitness <- read.csv(here("data/MC2/mc_G_log_fitness.csv"))
mc_G.fitness <- read.csv(here("data/MC2/mc_G_fitness.csv"))
mc_R_log.fitness <- read.csv(here("data/MC2/mc_R_log_fitness.csv"))
mc_R.fitness <- read.csv(here("data/MC2/mc_R_fitness.csv"))
mc_I_log.fitness <- read.csv(here("data/MC2/mc_I_log_fitness.csv"))
mc_I.fitness <- read.csv(here("data/MC2/mc_I_fitness.csv"))
mc_Ig_log.fitness <- read.csv(here("data/MC2/mc_Ig_log_fitness.csv"))
mc_Ig.fitness <- read.csv(here("data/MC2/mc_Ig_fitness.csv"))
mc_I_Ig_log.fitness <- read.csv(here("data/MC2/mc_I+Ig_log_fitness.csv"))
mc_I_Ig.fitness <- read.csv(here("data/MC2/mc_I+Ig_fitness.csv"))

examine variation

# plot fitness vs iteration
fitness.df <- rbind(
  cbind(mc_G_log.fitness, id = "Gametocyte\nlog10"),
  cbind(mc_G.fitness, id = "Gametocyte"),
  cbind(mc_R_log.fitness, id = "RBC log10"),
  cbind(mc_R.fitness, id = "RBC"),
  cbind(mc_I_log.fitness, id = "Asexual iRBC\nlog10"),
  cbind(mc_I.fitness, id = "Asexual iRBC"),
  cbind(mc_Ig_log.fitness, id = "Sexual iRBC\nlog10"),
  cbind(mc_Ig.fitness, id = "Sexual iRBC"),
  cbind(mc_I_Ig_log.fitness, id = "Asexual&sexual iRBC\nlog10"),
  cbind(mc_I_Ig.fitness, id = "Asexual&sexual\niRBC")
)

# quantify variance and mean
fitness_var.df <- fitness.df %>% 
  dplyr::group_by(id) %>% 
  dplyr::summarise(median = median(max_fitness)) %>% 
  dplyr::mutate(id = forcats::fct_reorder(id, median))

plot violin with difference in deterministic model fitness and mean model fitness

# get deterministic df
det.df <- data.frame(fitness_var.df, `Maximum fitness` =  c(8.49777, 9.494991,8.854682,9.573291,8.58856,9.561373,8.23991,8.181604,8.569285,9.618812)) %>% 
  dplyr::mutate(id = forcats::fct_reorder(id, median)) %>% 
  tidyr::pivot_longer(-id) %>% 
  mutate(classification = case_when(
    name == "Maximum.fitness" ~"Optimal single infection",
    name == "median" ~"Median Monte Carlo",
    name == "mean" ~ "Mean Monte Carlo"))

mc_a <- ggplot() +
  geom_point(data = det.df, aes(y = id, x = value, shape = classification, color = classification), size = 3, alpha = 0.8) +
  geom_violin(data = fitness.df, aes(y = id, x = max_fitness), fill = "transparent") +
  labs(x = "Fitness", y = "Cue", color = "Fitness", shape = "Fitness") +
  theme_bw() +
  theme(legend.position = "bottom") +
  scale_color_manual(values=c("black", "#4575b4", "#fc8d59"))

#————– plot together———————–#

# arrange the heat map
ggarrange(mc_a, mc_partition, ncol = 2, nrow = 1, labels = c("A", "B"), align = "h")
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

#——————————————–# # dual cue optimization figure #——————————————–#

source(here("functions/chabaudi_si_clean_high.R"))
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/par_to_hm_te.R"))

#———- plotting fitness of dual vs single cue opt ———# # import in previous data

plot

#———– time series conversion rate ————-# # dynamics simulation of high parameter cues (these serve as reference points)

plot

ggplot() +
  geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
  geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 3) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
  xlim(0, 20) +
  scale_color_manual(values = c("#fc8d59","#fdcb44","black", "#4575b4")) +
  theme_bw() +
  theme(legend.position="bottom") +
  guides(color = guide_legend(nrow = 2, byrow = TRUE))
Warning: Removed 3 rows containing missing values (`geom_line()`).
Warning: Removed 3 rows containing missing values (`geom_point()`).

#———— reaction norm heatmap of R log10 + I log10 ————# # process data

max(R_Ig.dyn$Ig) 
[1] 175754.2

plot

# just testing for sexual iRBC vs RBC
ggplot() +
  geom_path(data = R_Ig.dyn, aes(x = Ig, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
  geom_point(data = R_Ig.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = Ig, y = log_R), color = "white") +
  scale_x_continuous(trans = "log10") +
  xlim(0, 200000) +
  labs(y = "RBC log10", x = "Sexual iRBC log10", fill = "Conversion rate") +
  theme_dark()
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

save figure for poster

dual_rn.pl2 <- ggplot() +
  geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
  scale_fill_viridis_c() +
  geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
  geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
  xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
  ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
  labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion rate") +
  theme_dark() + theme(legend.position="top") 

dual_cr.pl2 <- ggplot() +
  geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
  geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 2) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
  xlim(0, 20) +
  scale_color_manual(values = c("#4575b4", "#91bfdb","#fc8d59","#fdcb44")) +
  theme_bw() +
  theme(legend.position="top") +
  guides(color = guide_legend(nrow = 2, byrow = TRUE))

ggarrange(dual_cr.pl2, dual_rn.pl2, align = "h", widths = c(1.25, 1))
ggsave(here("poster/dual_cue.png"), width = 7, height = 4)

#——– assemble final figure ————-#

# assemble panel B and C
dual_pl.BC <- ggarrange(dual_cr.pl, dual_rn.pl, align = "v", ncol = 1, labels = c("B", "C"))

# assemble panel A
ggarrange(dual_si_fitness.pl, dual_pl.BC, ncol = 2, labels = c("A", ""), widths = c(1, 0.75))
ggsave(here("figures/plos-bio/dual_cue.tiff"), units = "px", width = 2250, height = 1400, scale = 1.5, dpi=300,  bg = "white")

#============================================# # dynamics of dual cue simulation (all combinations) #============================================# # conversion rate

ggsave(here("figures/plos-bio/dual_cue_cr.tiff"), units = "px", width = 2000, height = 1500, dpi=300,  bg = "white")
Warning: Removed 26448 rows containing missing values (`geom_raster()`).

cumultative transmission transmission potential

Proving a point to myself

# it seems that R log+I log only inches ahead of other at the very end of the infection, suggesting that terminal investment is at play
ggplot(data = dual_tau.df_p, aes(x = time, y = value, color = label_plot)) +
  geom_line() +
  scale_fill_viridis_c() +
  xlim(15, 20) +
  ylim(5,10) +
  labs(x = "Time (days)", y = "Dual cue combination", fill = "Conversion rate") +
  theme_bw()
Warning: Removed 12500 rows containing missing values (`geom_line()`).

#============================================# # get dual cue disease map (simulated) #============================================# I am going to take the optimal dynamic (R log10 + I log10) and plot all possible disease curves and see if any follow the hysteresis curve. See below for real life disease curve.

process

plot

ggarrange(plotlist = dual_curve.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve1.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300,  bg = "white")


ggarrange(plotlist = dual_curve_xlog.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve2.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300,  bg = "white")


ggarrange(plotlist = dual_curve_ylog.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve3.tiff"), units = "px", width = 1000, height =1000, scale = 1.5, dpi=300,  bg = "white")


ggarrange(plotlist = dual_curve_log.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve4.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300,  bg = "white")

#============================================# # real life disease curve #============================================# # execute code from report 10 to get final dataset The following graphs will be made: - R vs iRBC - R log10 vs iRBC - R vs iRBC log10 - R log10 vs iRBC log10

R on y-axis

r_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = asex)) +
  geom_path(aes(y = RBC, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = asex)) +
  geom_path(aes(y = log10(RBC), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

r_ilog.dc <-ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = log10(asex))) +
  geom_path(aes(y = RBC, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = log10(asex))) +
  geom_path(aes(y = log10(RBC), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

G on y-axis

g_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = gam, x = asex)) +
  geom_path(aes(y = gam, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

glog_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(gam), x = asex)) +
  geom_path(aes(y = log10(gam), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

g_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = gam, x = log10(asex))) +
  geom_path(aes(y = gam, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

glog_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(gam), x = log10(asex))) +
  geom_path(aes(y = log10(gam), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

R vs G

r_g.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = gam)) +
  geom_path(aes(y = RBC, x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "Gametocyte per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_g.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = gam)) +
  geom_path(aes(y = log10(RBC), x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "Gametocyte per µL", y = "log10(RBC per µL)", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

r_glog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = log10(gam))) +
  geom_path(aes(y = RBC, x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(Gametocyte) per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_glog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = log10(gam))) +
  geom_path(aes(y = log10(RBC), x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(Gametocyte) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

plot together

#===========================================# # static competition #===========================================# #——- heat map —————# # calculate fitness difference for 20 days

static.ls <- lapply(static.ls, read_parquet)
Error: file must be a "InputStream"

import and process data

plot

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/static_competition_a.tiff"), units = "px", width = 2250, height = 1500, scale = 1.2, dpi=300,  bg = "white")

#—— effect cue perception ——-# ## logging

# get non-logged pairings
static_nolog <- static.df2 %>% 
  mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
         log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none")) %>% 
  filter(log_1 == "none")

static_log <- static.df2 %>% 
  mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
         log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none")) %>% 
  filter(log_1 == "log")

static_log.df <- left_join(
  select(static_nolog, cue_1, label_ci_2, log_1, None = fitness_difference),
  select(static_log, cue_1, label_ci_2, log_1, Log = fitness_difference),
  by = c("cue_1", "label_ci_2")) %>% 
  filter(!is.na(None) & !is.na(Log)) %>% 
  mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))

combined

static_nocomb <- static.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "none")

static_comb <- static.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "comb")
  
static_comb.df <- left_join(
  select(static_nocomb, cue_1, label_ci_2, log_1, Self = fitness_difference),
  select(static_comb, cue_1, label_ci_2, log_1, Total = fitness_difference),
  by = c("cue_1", "log_1", "label_ci_2")) %>% 
  filter(!is.na(Total) & !is.na(Self)) %>% 
  mutate(classification = ifelse(Total > Self, "Total better", "Self better"))

plot

ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")

ggsave(here("figures/plos-bio/static_competition_b.tiff"), units = "px", width = 1000, height = 2000, scale = 1.2, dpi=300,  bg = "white")

#===========================================# # invasion analysis #===========================================# # import in data (already 20 days )

invade.df <- read.csv(here("data/ci_invasion.csv"))

process data for invasion matrix

invade.mat <- invade.df %>% 
  group_by(V1 = pmin(mut_id, res_id), V2 = pmax(mut_id, res_id)) %>% # group by cue competition, irregardless of order
  mutate(id_alt = paste0(V1, V2),
         invade = case_when(
           fitness > 0 ~ "invade",
           fitness < 0 ~ "not invade"
         )) %>% 
  group_by(id_alt) %>% 
  mutate(
    mut_is_V1 = case_when(
    mut_id == V1 ~ "V1_invade",
    mut_id != V1 ~ "V1_invaded")) %>% 
  arrange(id_alt) %>% 
  select(fitness, V1, V2, id_alt, invade, mut_is_V1) %>% 
  tidyr::pivot_wider(names_from = mut_is_V1, values_from = fitness) %>% 
  group_by(id_alt) %>% 
  mutate(V1_invade2 = gsub("NA", "", paste0(V1_invade, collapse = "")),
         V1_invaded2 = gsub("NA", "", paste0(V1_invaded, collapse = ""))) %>% 
  distinct(id_alt, .keep_all = T) %>% 
  mutate(
    category = case_when(
    V1_invade2 > 0 & V1_invaded2 > 0 ~ "Mutual invasion",
    V1_invade2 > 0 & V1_invaded2 < 0 ~ "Only strain 1 invasion",
    V1_invade2 < 0 & V1_invaded2 > 0 ~ "Only strain 2 invasion",
    V1_invade2 < 0 & V1_invaded2 < 0 ~ "Mutual non-invasion"
  )) %>% 
  select(V1, V2, invasion = category)

invade.df %>% filter(mut_id == "G-i_none")
invade.df %>% filter(res_id == "G-i_none")
invade.mat4 <- rbind(
  select(invade.mat3, V1_label, V2_label, invasion),
  select(invade.mat3, V2_label = V1_label, V1_label = V2_label) %>% mutate(invasion = NA)) %>%
  mutate(
    invasion_2 = case_when(
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
    invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
  )) %>% 
  filter(!is.na(V1_label))
Adding missing grouping variables: `id_alt`
Adding missing grouping variables: `id_alt`

plot invasion matrix

create summary bar chart

# create a stacked barchart for summary
## filter out na
invade.matalt <- invade.mat3 %>% na.exclude()

# get frquency from both sides. Note when grouping for V2, from the perspective of cue 2, scenarrio when strain 2 invade = strain 1 invade
invade.matalt1 <- invade.matalt %>% group_by(V1_label, invasion) %>% 
  summarize(frequency_1 = n())

invade.matalt2 <- invade.matalt %>%
  mutate(invasion_alt = case_when(
    invasion == "Only strain 1 invasion" ~ "Only strain 2 invasion",
    invasion == "Only strain 2 invasion" ~ "Only strain 1 invasion",
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Mutual non-invasion" ~ "Mutual non-invasion"
  )) %>% 
  group_by(V2_label, invasion_alt) %>% 
  summarize(frequency_2 = n())     

# full join and sum. has confirmed all of them add up to 14 
invade.matalt3 <- full_join(invade.matalt1, invade.matalt2, by = c("V1_label" = "V2_label", "invasion" = "invasion_alt"))

invade.matalt3[is.na(invade.matalt3)] <- 0
invade.matalt4 <- invade.matalt3 %>% 
  mutate(freq = frequency_1 + frequency_2) %>% 
  mutate(temp = case_when(
    invasion == "Only strain 1 invasion" ~ freq
  )) %>% 
  group_by(V1_label) %>% 
  mutate(invade_1_freq = max(temp, na.rm = T)) %>% 
  mutate(invasion_2 = case_when(
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
    invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
  ))

plot together

ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))

ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggsave(here("figures/plos-bio/invasion_a.tiff"), units = "px", width = 2250, height = 1100, scale = 1.4, dpi=300,  bg = "white")

#—————- invasion pairwise comparison—————–# ## proces data

log

combined

invade_nocomb <- invade.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "none")

invade_comb <- invade.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "comb")
  
invade_comb.df <- left_join(
  select(invade_nocomb, cue_1, res_id, log_1, Self = fitness),
  select(invade_comb, cue_1, res_id, log_1, Total = fitness),
  by = c("cue_1", "log_1", "res_id")) %>% 
  filter(!is.na(Total) & !is.na(Self)) %>% 
  mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
invade_comb.df

plot

ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)

ggsave(here("figures/plos-bio/invasion_b.tiff"), units = "px", width = 2250, height = 850, scale = 1.2, dpi=300,  bg = "white")

#===========================================# # Cue performance across single, co-infection, static, and invasion #===========================================#

plot

#-=====================# # Partitioning best cue #=====================-# #——- single infection ———–# # redo some optimization (lower fitness in no R than default)

source(here("functions/chabaudi_si_clean_R.R"))
source(here("functions/chabaudi_si_clean_N.R"))
# I none
cl <- makeCluster(detectCores()); setDefaultCluster(cl = cl)
I_no_R <- optimParallel(
    par = rep(0.5,4), # start at 0.5x4
    fn = chabaudi_si_clean_R, 
    control = list(trace = 6, fnscale = -1),
    immunity = "tsukushi",
    parameters = parameters_tsukushi,
    time_range = seq(0, 20, by = 1e-3),
    cue_range =  seq(0, 6*(10^6), by = (6*(10^6))/5000),
    cue = "I",
    log_cue = "none",
    solver = "vode")
stopCluster(cl)
# 0.144021 -43.1046 2030.27 -524.686 
# 8.69589

import and process data

# import in data
si_partition.ls <- list.files(path = here("data/partition/si/"), pattern = "*.csv", full.names = T)
si_partition.ls <- lapply(si_partition.ls, read.csv)
si_partition.df <- do.call(rbind, si_partition.ls)

# combine with si fitness (default)
si_partition.df <- si_partition.df %>% left_join(select(si_fitness.df, id, fitness = value), by = "id")

# make longer
si_partition.df2 <- tidyr::pivot_longer(si_partition.df, c(fitness_R, fitness_N, fitness_W, fitness))

# calculate coefficient of variation. Also rename
si_partition.df2 <- si_partition.df2 %>% 
  group_by(name) %>% 
  mutate(cv = sd(value)/mean(value)*100,
         mean = mean(value),
         category = case_when(
           name == "fitness_R" ~ "No RBC limitation",
           name == "fitness_W" ~ "No targeted immunity",
           name == "fitness_N" ~ "No indiscriminate\nimmunity",
           name == "fitness" ~ "Default"
         ))

plot

library(ungeviz)
# raw fitness
si_partition.pl1 <- ggplot() +
  geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = mean, group = category, color = category), show.legend = F, size = 1) +
  geom_point(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value), size = 2, alpha = 0.7) +
  geom_line(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value, group = id), alpha = 0.2) +
  labs(x = "Fitness", y = "Conditions") +
  theme_bw()

# coefficient of variation
si_partition.pl2 <- ggplot() +
  geom_bar(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = cv), stat = "identity") +
  labs(x = "Coefficient of\nvariation (%)", y = "") +
  theme_bw() +
  theme(axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank())

si_partition.pl <- ggarrange(si_partition.pl1, si_partition.pl2, widths = c(1, 0.3), align = "h")
si_partition.pl

ggsave(here("figures/plos-bio/partition_fitness.tiff"), width = 7, height = 4)

#——- consequences of no targeted immunity ————# # get dynamics of no targeted immunity

get_dyn <- function(df){
  
  source(here("functions/chabaudi_si_clean_W.R"))
  id <- df$id
  cue <- df$cue
  log <- df$log
  par <- c(df$var_W1, df$var_W2, df$var_W3, df$var_W4)
  cue_range <- seq(df$low, df$high, by = df$by)
  
  # get dynamics
  dyn <- chabaudi_si_clean_W(
    parameters_cr = par,
    immunity = "tsukushi",
    parameters = parameters_tsukushi,
    time_range = seq(0, 20, by = 1e-3),
    cue_range =  cue_range,
    cue = cue,
    log_cue = log,
    solver = "vode",
    dyn = T
  )
  
  # combine
  dyn2 <- cbind(dyn, id = id, cue = cue, log = log)
  
  write_parquet(dyn2, paste0(here("data/partition/si_dyn/"), id, "_noW_dyn.parquet"))
  
}

get df to run

# join with cue_range
cue_range_si.df <- read.csv(here("data/cue_range_si.csv"))
si_partition.df3 <- si_partition.df %>% left_join(select(cue_range_si.df, low, high, by, id), "id")

# lapply loop
si_partition.ls <- split(si_partition.df3, seq(nrow(si_partition.df3)))
mclapply(si_partition.ls, get_dyn)

process dataframe

# import in dataframe
no_W.ls <- list.files(here("data/partition/si_dyn/"), pattern = "*noW_dyn.parquet", full.names = T)
no_W.df <- lapply(no_W.ls, read_parquet)
no_W.df <- do.call(rbind, no_W.df)

# combine with ez label
ez_label <- read.csv(here("data/ez_label.csv"))
no_W.df <- left_join(no_W.df, ez_label, by = c("id" = "id_si"))

# get conversion rate 
no_W.cr <- no_W.df %>% filter(variable == "cr")
no_W.I <- no_W.df %>% filter(variable == "I")

# get default conversion rate dynamics
si_dyn.df <- left_join(si_dyn.df, ez_label, by = c("id" = "id_si"))
si_dyn.cr <- si_dyn.df %>% filter(variable == "cr")
si_dyn.I <- si_dyn.df %>% filter(variable == "I")

plot conversion rate

mechanism: targeted immunity led to lower parasite density in the initial stages, which prevents parasites from making the switch from no conversion rate to high conversion rate. When parsite density undergoes drastic increase at the beginning due to lower immunity, this presents a higher degree of signal that allows parasite to make the switch appropriately

partition_cr.pl <- ggplot() +
  geom_line(data = no_W.cr, aes(x = time, y= value, color = "No targeted immunity")) +
  geom_line(data = si_dyn.cr, aes(x = time, y= value, color = "Default")) +
  facet_wrap(~ez_label_si, ncol = 5) +
  xlim(0, 20) +
  geom_vline(xintercept = 7) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Condition") +
  theme_bw()

no_W.cr

#—– cue state ————–#

function to get cue states

# function to get cue states
get_cue_state <- function(df){
  cue <- trimws(gsub("_log|_none", "", unique(df$id)))
  if(cue != "I+Ig"){
  df2 <- df %>% filter(variable == cue)
  if(str_detect(unique(df$id), "log")){
    df2 <- df2 %>% 
      mutate(value = log10(value))
  }
  }
  
  if(cue == "I+Ig"){
    df2 <- df %>% filter(variable %in% c("I", "Ig")) %>% 
      group_by(time) %>% 
      mutate(value = sum(value))
    
    if(str_detect(unique(df$id), "log")){
    df2 <- df2 %>% 
      mutate(value = log10(value))
  }
  }
  
  df2$value[df2$value == -Inf] <- 0
  
  write_parquet(df2, paste0(here("data/partition/si_default_state/"), unique(df$id), "_noW_state.parquet"))
}

run function

# split dynamics based on id
no_W.split <- split(no_W.df, no_W.df$id)

# run function
mclapply(no_W.split, get_cue_state)

# get dataframe
no_W.state <- list.files(here("data/partition/si_state/"), pattern = "*.parquet", full.names = T)
no_W.state <- lapply(no_W.state, read_parquet)
no_W.state <- do.call(rbind, no_W.state)
no_W.state$value[no_W.state$value < 0] <- 0

# get same for si infection
default.split <- split(si_dyn.df, si_dyn.df$id)
mclapply(default.split, get_cue_state)
default.state <- list.files(here("data/partition/si_default_state/"), pattern = "*.parquet", full.names = T)
default.state <- lapply(default.state, read_parquet)
default.state <- do.call(rbind, default.state)
default.state$value[default.state$value < 0] <- 0

# manually correct non-logging
I_Ig.corr <- no_W.state %>% filter(id == "I+Ig_log") %>% 
  mutate(value = log10(value))
I_Ig.corr$value[I_Ig.corr$value < 0] <- 0

no_W.state2 <- no_W.state %>% filter(id != "I+Ig_log")
no_W.state2 <- no_W.state2 %>% rbind(no_W.state2, I_Ig.corr)

plot

absence of targeted immunity led to drastic increase in parasite density in early phases of infection. This produces high signal intensity for parasite and host-based cues, especially non-logged ones, which allows for state differentation. While this can be viewed as a modelling artifiact, it should be noted that the logged cues seldom changed as these changes in early infection did little to alter the actual early signal intensity sensed by the parasite. In an environment where there is heterogeneity in host response, and thus, signal, logging allows for parasites to adapt optimal strategy whereas non-logged cues must contend with sensitivity to immunity.

# function to individually plot stuff
plot_state <- function(df1, df2){
  
  # plot state dynamics
  state_pl <- ggplot() +
  geom_line(data = df1, aes(x = time, y = value, color = name, group = name)) +
  facet_wrap(~ez_label_si, scales = "free") +
  xlim(1,20) +
  theme_bw() +
  theme(legend.position="none") +
  labs(x = "", y = "Cue") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE)) +
  scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59"))
  
  # plot conversion rate dynamics
  cr_pl <- ggplot() +
  geom_raster(data = df2, aes(x = time, y = name, fill = value)) +
  xlim(1,20) +
  theme_bw() +
    labs(x = "Time (days)") +
  theme(axis.title.y=element_blank(),
        axis.ticks.y=element_blank(),
        legend.position = "none") +
    scale_fill_viridis_c(lim = c(0, 1))
  
  # arrange
  ggarrange(state_pl, cr_pl, ncol = 1, nrow = 2, align = "v", heights = c(1, 0.4))
  ggsave(paste0(here("figures/plos-bio/partition/"), unique(df1$id), ".tiff"), width = 4.5, height = 3.5)
}

split

# combine state
noW_default.state <- left_join(
  select(no_W.state2, time, `No targeted\nimmunity` = value, id, ez_label_si), 
  select(default.state %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))

noW_default.state2 <- tidyr::pivot_longer(noW_default.state, c(`No targeted\nimmunity`, `Default`))
# combine conversion raster
noW_default.cr <- left_join(
  select(no_W.cr, time, `No targeted\nimmunity` = value, id, ez_label_si), 
  select(si_dyn.cr %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.cr2 <- tidyr::pivot_longer(noW_default.cr, c(`No targeted\nimmunity`, `Default`))

# split
noW_default_state.ls <- split(noW_default.state2, noW_default.state2$id)
noW_default_cr.ls <- split(noW_default.cr2, noW_default.cr2$id)

# run function
mapply(plot_state, noW_default_state.ls, noW_default_cr.ls)

#——– reaction norms of default vs optimized ————# # get reaction norm and rug data

source(here("functions/par_to_df.R"))

# Gametocyte
g_log.rn <- par_to_df(par = c(1.211521, -3.936778,  -1.312944,  -1.285713), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g_log.rn2 <- par_to_df(par = c(1.393860539, -4.253007616,   -0.313947029,   -2.000857344), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))

g.rn <- par_to_df(par = c(0.04061288,   -9.31445958,    74.13015506,    -431.5984364), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
g.rn2 <- par_to_df(par = c(0.541729073, -3.904616443,   0.87487412, -0.694177021), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))

# I+Ig
I_Ig_log.rn <- par_to_df(par = c(3.594042,  4.157744,   -13.530672, 2.599905), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig_log.rn2 <- par_to_df(par = c(63.71893822,  -87.77671601,   -56.55475514,   -66.02209549), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))

I_Ig.rn <- par_to_df(par = c(0.3159297, -46.1104558,    1250.752908,    -6.1982093), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
I_Ig.rn2 <- par_to_df(par = c(0.731982784,  -21.69799449,   149.7841876,    17.02551769), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))

# convert log to non-logged scale
g_log.rn$cue_range <- 10^(g_log.rn$cue_range)
g_log.rn2$cue_range <- 10^(g_log.rn2$cue_range)
I_Ig_log.rn$cue_range <- 10^(I_Ig_log.rn$cue_range)
I_Ig_log.rn2$cue_range <- 10^(I_Ig_log.rn2$cue_range)

# get rug
g_log.rug <- default.state %>% 
  filter(label_si == "G log") %>% 
  mutate(value = 10^value) %>% 
  select(label_si, value)

g_log.rug2 <- no_W.state %>% 
  filter(label_si == "G log") %>% 
  mutate(value = 10^value) %>% 
  filter(value <= 6*(10^4)) %>% 
  select(label_si, value)

I_Ig_log.rug <- default.state %>% 
  filter(label_si == "I+Ig log") %>% 
  select(label_si, value)

I_Ig_log.rug2 <- no_W.state %>% 
  filter(label_si == "I+Ig log") %>% 
  select(label_si, value)

g.rug <- default.state %>% 
  filter(label_si == "G") %>% 
  select(label_si, value)

g.rug2 <- no_W.state %>% 
  filter(label_si == "G" & value <= 6*(10^4)) %>% 
  select(label_si, value)

I_Ig.rug <- default.state %>% 
  filter(label_si == "I+Ig") %>% 
  select(label_si, value)

I_Ig.rug2 <- no_W.state %>% 
  filter(label_si == "I+Ig") %>% 
  select(label_si, value)

# get rug limits
rug_lim <- rbind(g_log.rug,
                 g_log.rug2,
                 I_Ig_log.rug,
                 I_Ig_log.rug2,
                 g.rug,
                 g.rug2,
                 I_Ig.rug,
                 I_Ig.rug2) %>% 
  group_by(label_si) %>% 
  summarize(max = max(hablar::s(value), na.rm = T),
            min = min(hablar::s(value), na.rm = T))

# combine and filter
rn <- rbind(
  cbind(g_log.rn, label_si = "G log", condition = "Default"),
  cbind(g_log.rn2, label_si = "G log", condition = "No targeted\nimmunity"),
  cbind(g.rn, label_si = "G", condition = "Default"),
  cbind(g.rn2, label_si = "G", condition = "No targeted\nimmunity"),
  cbind(I_Ig_log.rn, label_si = "I+Ig log", condition = "Default"),
  cbind(I_Ig_log.rn2, label_si = "I+Ig log", condition = "No targeted\nimmunity"),
  cbind(I_Ig.rn, label_si = "I+Ig", condition = "Default"),
  cbind(I_Ig.rn2, label_si = "I+Ig", condition = "No targeted\nimmunity")
) %>% 
  left_join(rug_lim, by = "label_si") %>% 
  group_by(label_si) %>% 
  filter(cue_range <= max & cue_range >= min)

# combine rug
rug <- rbind(cbind(g_log.rug, condition = "Default"),
             cbind(g_log.rug2, condition = "No targeted\nimmunity"),
             cbind(g.rug, condition = "Default"),
             cbind(g.rug2, condition = "No targeted\nimmunity"),
             cbind(I_Ig_log.rug, condition = "Default"),
             cbind(I_Ig_log.rug2, condition = "No targeted\nimmunity"),
             cbind(I_Ig.rug, condition = "Default"),
             cbind(I_Ig.rug2, condition = "No targeted\nimmunity"))

# cobine with ezlabel
rn2 <- rn %>% left_join(ez_label, by = "label_si")
rug2 <- rug %>% left_join(ez_label, by = "label_si")

# filter rug
default.rug <- rug2 %>% filter(condition == "Default")
no.rug <- rug2 %>% filter(condition == "No targeted\nimmunity")

plot

ggplot() +
  geom_line(data = rn2, aes(x = cue_range, y = cr, color = condition)) +
  geom_rug(data = default.rug, aes(x = value, color = condition), sides = "b") +
  geom_rug(data = no.rug, aes(x = value, color = condition), sides = "t") +
  facet_wrap(~fct_relevel(ez_label_si, c("Gametocyte log10", "Gametocyte", "Asexual&sexual\niRBC log10", "Asexual&sexual iRBC")), scales = "free_x") +
  scale_x_continuous(labels = function(x) format(x, scientific = TRUE)) +
  theme_bw() +
  scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59")) +
  ylim(0, 1.1) +
  labs(x = "Cue range", y = "Conversion rate", color = "Condition")

ggsave(here("figures/plos-bio/partition_rn.tiff"), width = 7.5, height = 6)

get conversion rate legend

noW_default.cr %>% filter(id == "G_log") %>% 
ggplot() +
  geom_raster(aes(x = time, y = id, fill = Default)) +
  xlim(1,20) +
  theme_bw() +
    labs(x = "Time (days)",
         fill = "Conversion rate") +
  theme(axis.title.y=element_blank(),
        axis.ticks.y=element_blank(),) +
    scale_fill_viridis_c(lim = c(0, 1))

ggsave(here("figures/plos-bio/cr_legend.tiff"))

#================================# # Disease curves for single, co-infection, and invasion #===============================# # get data for disease curves

# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet")) 

# co-infection dynamics (mon-cue)
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))

# dual cue dynamics
dual_dyn.df <- read_parquet(here("data/dual_cue_dyn/dual_cue_dyn.parquet"))

#——- single cue comparison —————# # process data

# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>% 
  filter(variable == "I" | variable == "Ig" | variable == "R") %>% 
  tidyr::pivot_wider(names_from = variable, values_from = value) %>% 
  mutate(total = I+Ig)
# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>% 
  filter(variable == "I" | variable == "Ig" | variable == "R") %>% 
  tidyr::pivot_wider(names_from = variable, values_from = value) %>% 
  mutate(total = I+Ig)

plot

#———- co-infection monocue ————-#

# get relevent variables
ci_dc.df <- ci_dyn.df %>% 
  filter(variable == "I1" | variable == "Ig1" | variable == "R")

# morph into skinny format
ci_dc.df <- tidyr::pivot_wider(ci_dc.df, names_from = variable, values_from = value, id_cols = c(time, label)) %>% 
  mutate(total = I1+Ig1)

# good cue bad cue
ci_cue.dv <- ci_fitness.df %>% 
  mutate(classification = case_when(
    value > 2.25 ~ "High-performing",
    value <= 2.25 ~ "Poor-performing"
  ))

# join with classificaiton
ci_dc.df2 <- ci_dc.df %>% left_join(ci_cue.dv, by = "label")

# split into top erforming and poor-performing cues
ci_dc.high <- ci_dc.df2 %>% filter(classification == "High-performing")
ci_dc.poor <- ci_dc.df2 %>% filter(classification == "Poor-performing")

# join high performing with label
ci_dc.high2 <- ci_dc.high %>% left_join(ez_label, by = c("label" = "label_ci"))

#write_parquet(ci_dc.high2, here("data/disease_curve/ci_dc_high.parquet"))
#write_parquet(ci_dc.poor, here("data/disease_curve/ci_dc_poor.parquet"))

plot

ci_dc.poor <- read_parquet(here("data/disease_curve/ci_dc_poor.parquet"))
ci_dc.high2 <- read_parquet(here("data/disease_curve/ci_dc_high.parquet"))

# plot
ci_dc.pre <- ggplot() +
  geom_path(data = ci_dc.poor, aes(x= total, y = R, group = label), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Co-infection\ngood performing cues", x = "Asexual & sexual iRBC per µL", y = "RBC per µL") +
  theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
  guides(shape = FALSE)

ci_dc.pl <- ci_dc.pre +
  geom_point(data = ci_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, color = ez_label, shape = ez_label), size = 3) +
  geom_path(data = ci_dc.high2, aes(x= total, y = R, group = ez_label, color = ez_label), size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  scale_color_manual(values=c( "#4575b4", "#fc8d59", "#fdcb44", "#91bfdb")) +
  guides(color = guide_legend(override.aes = list(size = 0.1)))

#——— dual cue ————————–# # process data

plot

dual_dc.high <- read_parquet(here("data/disease_curve/dual_dc_high.parquet"))
dual_dc.poor <- read_parquet(here("data/disease_curve/dual_dc_poor.parquet"))

dual_dc.high2 <- dual_dc.high %>% 
  filter(label_alt == "R log10 + I log10")

# add 
dual_dc.pre <- ggplot() +
  geom_path(data = dual_dc.poor, aes(x= total, y = R, group = label_alt), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "High-performing\ndual cues per µL", x = "Asexual & sexual iRBC", y = "RBC per µL") +
  theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
  guides(shape = FALSE)


dual_dc.pl <- dual_dc.pre +
  geom_point(data = dual_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, shape = label_alt), color = "#4575b4", size = 3) +
  geom_path(data = dual_dc.high2, aes(x= total, y = R, group = label_alt), color = "#4575b4", size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme(legend.position = "none") +
  guides(color = guide_legend(override.aes = list(size = 0.1)))

#——— co-infection static —————-#

# import in dynamics data
static_dyn.ls <- list.files(path = here("data/ci_static/"), pattern = "*.parquet", full.names = T)
static_dyn.ls <- lapply(static_dyn.ls, read_parquet)

# filter variable and transform
static_dyn.ls2 <- mclapply(static_dyn.ls, function(x){
  x %>% 
    filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>% 
    mutate(id_alt = paste(id_1, id_2)) %>% 
    tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
  mutate(total1 = I1+Ig1, total2 = I2+Ig2)
})

static_dc.df <- do.call(rbind, static_dyn.ls2)
static_dc.df <- static_dc.df %>% 
  mutate(id_1 = gsub(" .*", "", id_alt),
         id_2 = gsub(".* ", "", id_alt)) %>% 
  filter(id_1 != id_2)
#write_parquet(static_dc.df, here("data/disease_curve/static_dc.parquet"))

further processing

static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
# get winners and losers
## import in fitness
static_fitness.df <- read.csv(here("data/ci_static.csv"))
## get winner situation
static_fitness.df2 <- static_fitness.df %>% 
  filter(id_1 != id_2) %>% 
  mutate(winning_id = case_when(
    fitness_difference > 0 ~ id_1,
    fitness_difference< 0 ~ id_2
  ),
  losing_id = case_when(
    fitness_difference < 0 ~ id_1,
    fitness_difference> 0 ~ id_2
  ))

# left join
static_dc.df2 <- static_dc.df %>% 
  left_join(select(static_fitness.df2, id_1, id_2, winning_id, losing_id, fitness_difference), by = c("id_1", "id_2"))

# get winner-loser difference in terms of I+Ig also filter out to onyl very strong fitness difference
static_dc.df3 <- static_dc.df2 %>% 
  mutate(total_diff = case_when(
    fitness_difference > 0 ~ total1-total2,
    fitness_difference< 0 ~ total2-total2
  ),
  total_winner = case_when(
    fitness_difference > 0 ~ total1,
    fitness_difference< 0 ~ total2
  ),
  total_loser = case_when(
    fitness_difference > 0 ~ total2,
    fitness_difference< 0 ~ total1
  )) %>% 
  filter(abs(fitness_difference) > 0.5)

plot

static_dc.pl <- ggplot() +
  geom_path(data = static_dc.df3, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  geom_path(data = static_dc.df3, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
          alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
  scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59"))  +
  theme_bw() + 
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1))

#———co-infection invasion —————# # get invasion dynamic

# get invasion df
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))

# get cue range
ci_cue_range <- read.csv(here("data/cue_range_ci.csv"))
invasion_fitness.df2 <- invasion_fitness.df %>% 
  left_join(select(ci_cue_range, id, mut_cue = cue, mut_low = low, mut_high = high, mut_by = by), by = c("mut_id"= "id")) %>% 
  left_join(select(ci_cue_range, id, res_cue = cue, res_low = low, res_high = high, res_by = by), by = c("res_id"= "id"))

function to get dynamic

get_invasion_dyn <- function(df){
  # get cues
  mut_cue <- df$mut_cue
  res_cue <- df$res_cue
  
  # get info of cues (for co infection)
  if(stringr::str_detect(mut_cue, "-i")){mut_cue = gsub("*-i", "1", mut_cue)}
  if(stringr::str_detect(mut_cue, "-i", negate = T)){mut_cue = mut_cue}
  if(stringr::str_detect(res_cue, "-i")){res_cue = gsub("*-i", "2", res_cue)}
  if(stringr::str_detect(res_cue, "-i", negate = T)){res_cue = res_cue}
  
  # get log
  mut_log <- ifelse(stringr::str_detect(df$mut_id, "log"), "log10", "none")
  res_log <- ifelse(stringr::str_detect(df$res_id, "log"), "log10", "none")
  
  # get parameters
  mut_par <- c(df$mut_var1_opt, df$mut_var2_opt, df$mut_var3_opt, df$mut_var4_opt)
  res_par <- c(df$res_var1, df$res_var2, df$res_var3, df$res_var4)
  
  # get cue range
  mut_cue_range <- seq(df$mut_low, df$mut_high, by = df$mut_by)
  res_cue_range <- seq(df$res_low, df$res_high, by = df$res_by)
  
  # get dynamics of co infection
  ci_dyn <- chabaudi_ci_clean(
    parameters_cr_1 = mut_par,
    parameters_cr_2 = res_par,
                  immunity = "tsukushi",
                  parameters = parameters_tsukushi,
                  cue_1 = mut_cue,
                  cue_2 = res_cue,
                  cue_range_1 = mut_cue_range,
                 cue_range_2 = res_cue_range,
                log_cue_1 = mut_log,
                log_cue_2 = res_log,
                solver = "vode",
                time_range = seq(0, 30, 0.001),
    dyn = T)
  
  # append label to all df
 ci_dyn2 <- cbind(ci_dyn, mut_id = df$mut_id, res_id = df$res_id)
  
  # write
 write_parquet(ci_dyn2, paste0(here("data/ci_invasion_dyn/"), df$mut_id, "-", df$res_id, ".parquet"))
}

run dynamic funciton

# get function and parameters
source(here("functions/chabaudi_ci_clean.R"))
parameters_tsukushi <- c(R1 = 8.89*(10^6), # slightly higher
                lambda = 3.7*(10^5),
                mu = 0.025, 
                p = 8*(10^-6), # doubled form original
                alpha = 1, 
                alphag = 2, 
                beta = 5.721, 
                mum = 48, 
                mug = 4, 
                I0 = 43.85965, 
                Ig0 = 0, 
                a = 150, 
                b = 100, 
                sp = 1,
                psin = 16.69234,
                psiw = 0.8431785,
                phin = 0.03520591, 
                phiw = 550.842,
                iota = 2.18*(10^6),
                rho = 0.2627156)
# split
invasion.ls <- split(invasion_fitness.df2, seq(nrow(invasion_fitness.df2)))

# run function
mclapply(invasion.ls, get_invasion_dyn, mc.cores = 4)

process data

# import in invasion dynamics
invasion_dyn.ls <- list.files(path = here("data/ci_invasion_dyn"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls <- lapply(invasion_dyn.ls, read_parquet)

# filter and so on
invasion_dyn.ls2 <- mclapply(invasion_dyn.ls[167:177], mc.cores = 4, function(x){
  x2 <- x %>% 
    filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>% 
    mutate(id_alt = paste(mut_id, res_id)) %>% 
    select(id_alt, time, variable, value) %>% 
    tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
  mutate(total1 = I1+Ig1, total2 = I2+Ig2)
  
  write_parquet(x2, paste0(here("data/disease_curve/ci_invasion/"), unique(x2$id_alt), "_dc.parquet"))
})

# fetch data
invasion_dyn.ls2 <- list.files(path = here("data/disease_curve/ci_invasion"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls2 <- lapply(invasion_dyn.ls2, read_parquet)
invasion_dc.df <- do.call(rbind, invasion_dyn.ls2)
invasion_dc.df <- invasion_dc.df %>% 
  mutate(mut_id = gsub(" .*", "", id_alt),
         res_id = gsub(".* ", "", id_alt)) %>% 
  filter(mut_id != res_id)
#write_parquet(invasion_dc.df, here("data/disease_curve/invasion_dc.parquet"))

further processing

invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
# get winners and losers
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
invasion_dc.df2 <- invasion_dc.df %>% 
  left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>% 
  mutate(
  total_winner = case_when(
    fitness> 0 ~ total1,
    fitness< 0 ~ total2
  ),
  total_loser = case_when(
    fitness > 0 ~ total2,
    fitness < 0 ~ total1
  )) %>% 
  filter(abs(fitness) > 0.5)

plot

invasion_dc.pl <- ggplot() +
  geom_path(data = invasion_dc.df2, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  geom_path(data = invasion_dc.df2, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
          alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
  scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59"))  +
  theme_bw() + 
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) %>% 
  theme(legend.position = "none")

#——— quantifying disease curve area ————# # function to calculate area between sets of points -> from https://stackoverflow.com/questions/3672260/area-covered-by-a-point-cloud-with-r

library(splancs)
Loading required package: sp

Spatial Point Pattern Analysis Code in S-Plus
 
 Version 2 - Spatial and Space-Time analysis


Attaching package: ‘splancs’

The following object is masked from ‘package:dplyr’:

    tribble
cha<-function(df){
  x <- df$total
  y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}
library(splancs)
cha<-function(df){
  x <- df$total
  y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}

loop to get area: single infection

# join with fitness
si_fitness.df <- si_fitness.df %>% left_join(ez_label, by = c("id" = "id_si"))
Error in is.data.frame(y) : object 'ez_label' not found

coinfection

# split
ci_dc_high.ls <- split(ci_dc.high2, ci_dc.high2$ez_label)
ci_dc_poor.ls <- split(ci_dc.poor, ci_dc.poor$label)

# run function to find area
ci_dc_high.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_high.ls, cha)), id_alt = names(lapply(ci_dc_high.ls, cha)), value = unique(ci_dc.high2$value))

ci_dc_poor.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_poor.ls, cha)), id_alt = names(lapply(ci_dc_poor.ls, cha)), value = unique(ci_dc.poor$value))

# edit and join
ci_dc_high.area2 <-  ci_dc_high.area %>% 
  select(area, value) %>% 
  mutate(condition = "Co-infection")

ci_dc_poor.area2 <-  ci_dc_poor.area %>% 
  select(area, value) %>% 
  mutate(condition = "Co-infection")

dual cue

# split
dual.dc <- read_parquet(here("data/disease_curve/dual_dc.parquet"))
dual_dc.ls <- split(dual.dc, dual.dc$label_alt)

# get area
dual_dc.area <- cbind.data.frame(area = as.numeric(lapply(dual_dc.ls, cha)), id_alt = names(lapply(dual_dc.ls, cha)))

# bind with fitness
dual_fitness.df <- dual_fitness.df %>% mutate(id_alt = paste(label, "+", label_b))
dual_dc.area2 <- dual_dc.area %>% 
  left_join(dual_fitness.df, by = "id_alt") %>% 
  select(area, value) %>% 
  mutate(condition = "Dual-cue") %>% 
  filter(value > 2)
dual_dc.area2

#—— get fitted scatter plot for all single infection, co infection, and dual cue ——–#

# plot
library("ggpmisc")
Loading required package: ggpp

Attaching package: ‘ggpp’

The following object is masked from ‘package:ggplot2’:

    annotate

#——- plot together with disease curve ——–#

# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# co-infection
ci_vir.pl <- ggarrange(ci_dc.pl, ci_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

#——— static area comparison ————-# # compute area

# import in dc dynamic and fitness
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
static_fitness.df <- read.csv(here("data/ci_static.csv"))

# get winner and loser
static_dc.df4 <- static_dc.df %>% 
  left_join(select(static_fitness.df, id_1, id_2, fitness_difference), by = c("id_1", "id_2")) %>%
  filter(id_1 != id_2) %>% 
  mutate(
  total_winner = case_when(
    fitness_difference > 0 ~ total1,
    fitness_difference< 0 ~ total2
  ),
  total_loser = case_when(
    fitness_difference > 0 ~ total2,
    fitness_difference< 0 ~ total1
  ))%>% 
  filter(abs(fitness_difference) > 0.5)

# split by winner and loser
static_dc.ls1 <- split(select(static_dc.df4, R, total = total_winner), static_dc.df4$id_alt)
static_dc.ls2 <- split(select(static_dc.df4, R, total = total_loser), static_dc.df4$id_alt)

# get area
static_win.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls1, cha)), status = "Winner")
static_loser.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls2, cha)), status = "Loser")

# pair
static.area <- cbind(select(static_win.area, Winner = area),
                     select(static_loser.area, Loser = area)) %>% 
  mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))

plot static

#——— invasion area comparison —————–# # get area

# import in dc dynamic and fitness
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))

invasion_dc.df4 <- invasion_dc.df %>% 
  left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>% 
  mutate(
  total_winner = case_when(
    fitness> 0 ~ total1,
    fitness< 0 ~ total2
  ),
  total_loser = case_when(
    fitness > 0 ~ total2,
    fitness < 0 ~ total1
  )) %>% 
  filter(abs(fitness) > 0.5)

# split by winner and loser
invasion_dc.ls1 <- split(select(invasion_dc.df4, R, total = total_winner), invasion_dc.df4$id_alt)
invasion_dc.ls2 <- split(select(invasion_dc.df4, R, total = total_loser), invasion_dc.df4$id_alt)

# get area
invasion_win.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls1, cha)), status = "Winner")
invasion_loser.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls2, cha)), status = "Loser")

# pair
invasion.area <- cbind(select(invasion_win.area, Winner = area),
                     select(invasion_loser.area, Loser = area)) %>% 
  mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))

plot

#—— plot together ————-#

# pairwise comparison for static and invasive comeptition
heterocue_comp.pl <- ggarrange(static_area.pl, invasion_area.pl, ncol = 2, nrow = 1, align = "v")

# join inthe other disease curves
ggarrange(si_vir.pl, ci_vir.pl, dual_vir.pl, heterocue_comp.pl, ncol = 2, nrow = 2, labels = c("A", "B", "C", "D"), heights = c(1, 0.8))

ggsave(here("figures/plos-bio/virulence.tiff"), units = "px", width = 2250, height = 1600, scale = 1.9, dpi=300, bg = "white")

#====================================# # dual cue dynamics figure #===================================#

get dual dynamics

dual.dyn <- chabaudi_si_clean(
  parameters_cr = c(4.446192033,    10.97518275,    1.38762817, 23.3059254, -3.452052371,   -18.0070692,    39.66614226,    -3.545193141,   18.78350799),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 30, by = 1e-3),
  cue_range =  seq(6, 7, by = 1/500),
  cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
  cue = "R",
  cue_b = "I",
  log_cue = "log10",
  log_cue_b = "log10",
  solver = "vode",
  dyn = T
)

# filter out relevent dataframes
dual.dyn_f <- dual.dyn %>% 
  filter(variable %in% c("I", "Ig", "G", "R", "N", "W"))

# cr only
dual.dyn_cr <- dual.dyn %>% filter(variable == "cr")

plot

dual_I.plt <- ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "I"), aes(x = time, y = value/(10^5)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "I" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^5, name="Asexual iRBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_Ig.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "Ig"), aes(x = time, y = value/(10^5)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "Ig" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^5, name="Sexual iRBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_G.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "G"), aes(x = time, y = value/(10^4)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "G" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^4)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^4, name="Gametocyte per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_R.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "R"), aes(x = time, y = value/(10^7)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "R" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^7)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^7, name="RBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_N.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "N"), aes(x = time, y = value*10),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "N" & row_number() %% 1000 == 0), 
             aes(x = time, y = value*10), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*0.1, name="Indiscriminate immunity")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_W.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "W"), aes(x = time, y = value*2),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "W" & row_number() %% 1000 == 0), 
             aes(x = time, y = value*2), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*0.5, name="Targeted immunity")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

plot together

ggarrange(dual_I.plt, dual_Ig.plt, dual_G.plt, dual_R.plt, dual_N.plt, dual_W.plt, nrow = 3, ncol = 2, align = "hv", labels = c("A", "B", "C", "D", "E", "F"))
ggsave(here("figures/plos-bio/dual_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1, dpi=300, bg = "white")

#======================================# # Single and co-infection verification #======================================# # single infection

# import in all single infection data
si_val.ls <- list.files(path = here("data/si_validation"), pattern = "*.csv", full.names = T)

si_val.df <- lapply(si_val.ls, read.csv)
si_val.df <- do.call(rbind, si_val.df)

# get max fitness from simulation. left join with si_opt
si_opt.df <- read.csv(here("data/si_opt.csv"))

# we can see that all of the randomly simulated models have a fitness value that is less than the optimized model
si_val.df2 <- select(si_val.df, V1, id) %>%
  left_join(si_opt.df, by =c("id" = "id")) %>% 
  mutate(fitness_difference = fitness_20 - V1) %>% 
  left_join(select(ez_label, id_si, ez_label_si), by = c("id" = "id_si"))

Model validation

plot

si_val.plt <- ggplot(data = si_val.df2, aes(x = fitness_difference)) +
  geom_histogram(bins = 50) +
  geom_vline(xintercept = 0, color = "#fc8d59") +
  facet_wrap(~ez_label_si, scales = "free", ncol = 3) +
  labs(x = "Optimized fitness - random fitness", y = "Frequency") +
  theme_bw()

ci_val.plt <- ggplot(data = ci_val.df2, aes(x = V1)) +
  geom_histogram(bins = 50) +
  geom_vline(xintercept = 0, color = "#fc8d59") +
  facet_wrap(~ez_label, scales = "free", ncol = 4) +
  labs(x = "Fitness difference between\noptimized and random strain", y = "Frequency") +
  theme_bw()

ggarrange(si_val.plt, ci_val.plt, align = "hv", labels = c("A", "B"), widths = c(3,4))
ggsave(here("figures/plos-bio/validation.tiff"), units = "px", width = 2250, height = 1300, scale = 1.6, dpi=300, bg = "white")

#=========================# # Monte carlo dynamics supplementary #=========================# # run code in report 16

mc_dyn_a <- ggplot() +
  geom_line(data = reference.df, aes(x = time, y = cr)) +
  geom_ribbon(data = diff.df, aes(x = time, ymin = cr_bot, ymax = cr_top), alpha = 0.5, fill = "#fc8d59") +
  facet_wrap(~cue, ncol = 2) +
  labs(x = "Time (days)", y = "Conversion rate") +
  theme_bw()
  
# plot fitness timeseries. When if tiness lost? At the latter part
mc_dyn_b  <- ggplot() +
  geom_line(data = reference.df, aes(x = time, y = tau)) +
  geom_ribbon(data = diff.df, aes(x = time, ymin = tau_bot, ymax = tau_top), alpha = 0.5, fill = "#fc8d59") +
  facet_wrap(~cue, ncol = 2) +
  labs(x = "Time (days)", y = "Transmission potential") +
  theme_bw()

ggarrange(mc_dyn_a, mc_dyn_b, ncol = 1, align = "v", labels = c("A", "B"))
Warning: Removed 1 row containing missing values (`geom_line()`).
ggsave(here("figures/plos-bio/MC_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1.3, dpi=300, bg = "white")

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkZVNvbHZlKQpsaWJyYXJ5KGNyb25lKQpsaWJyYXJ5KG9wdGltUGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShkb1JORykKbGlicmFyeShhcnJvdykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShzY2FsZXMpCmBgYAoKTm90ZWJvb2sgZm9yIHBsb3R0aW5nIGFsbCBvZiB0aGUgZmlndXJlcyBmb3IgUGxvUyBCaW9sb2d5IG1hbnVzY3JpcHQgc3VibWlzc2lvbgoKR3VpZGVsaW5lczogdGFrZW4gZnJvbSBodHRwczovL2pvdXJuYWxzLnBsb3Mub3JnL3Bsb3NiaW9sb2d5L3MvZmlndXJlcyNsb2MtZmlndXJlLWZpbGUtcmVxdWlyZW1lbnRzCjEuIGZvcm1hdDogZXBzCjIuIG1heCBmaWxlIHNpemU6IDEwIE1CCjMuIHRleHQgc2l6ZTogQXJpYWwsIFRpbWVzLCBvciBTeW1ib2wgZm9udCBvbmx5IGluIDgtMTIgcG9pbnQKMi4gZmlndXJlIHNpemU6IFdpZHRoOiA3ODkg4oCTIDIyNTAgcGl4ZWxzIChhdCAzMDAgZHBpKS4gSGVpZ2h0IG1heGltdW06IDI2MjUgcGl4ZWxzIChhdCAzMDAgZHBpKS4KCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCmZpZ3VyZSAxOiBiZXN0IHNpbmdsZSBhbmQgY28taW5mZWN0aW9uIGN1ZQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCkZpZ3VyZSBkaXNwbGF5aW5nIHRoZSByZWFjdGlvbiBub3JtcyBvZiBiZXN0IHNpbmdsZSBhbmQgY28taW5mZWN0aW9uLgoKIy0tLS0tLS0gb3B0aW1hbCBjdWUgcmVhY3Rpb24gbm9ybSAtLS0tLS0tLS0tLSMKIyByZWFkIGRhdGEKYGBge3J9CiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljcywgcmVhY3Rpb24gbm9ybXMsIGFuZCBydWdzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCnNpX3JuLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9ybi5wYXJxdWV0IikpCnNpX3J1Zy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfcnVnLnBhcnF1ZXQiKSkgJT4lIAogIGRpc3RpbmN0KHZhbHVlLCBsYWJlbCwgLmtlZXBfYWxsID0gVCkKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzLCByZWFjdGlvbiBub3JtcywgYW5kIHJ1Z3MKY2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9keW4ucGFycXVldCIpKQpjaV9ybi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfcm4ucGFycXVldCIpKQpjaV9ydWcuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX3J1Zy5wYXJxdWV0IikpICU+JSAKICBkaXN0aW5jdCh2YWx1ZSwgbGFiZWwsIC5rZWVwX2FsbCA9IFQpCgpjaV9ydWcuZGYKYGBgCgojIHByb2Nlc3MgZGF0YSBmb3IgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBpbXBvcnQgbGFiZWxsaW5nIHNjaGVtZQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBnZXQgc2lfbGFiZWwgd2l0aCBjaSBjdWUgcmFuZ2UKc2lfY2lfcnVnLmRmIDwtIGNpX3J1Zy5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX3NpID0gY2FzZV93aGVuKAogICAgbGFiZWwgJWluJSBjKCJJIiwgIkkxK0kyIikgfiAiSSIsCiAgICBsYWJlbCAlaW4lIGMoIkkgbG9nIiwiSTErSTIgbG9nIikgfiAiSSBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJJZyIsICJJZzErSWcyIikgfiAiSWciLAogICAgbGFiZWwgJWluJSBjKCJJZyBsb2ciKSB+ICJJZyBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJzdW0iLCAiSStJZyIpIH4gIkkrSWciLAogICAgbGFiZWwgJWluJSBjKCJzdW0gbG9nIiwgIkkrSWcgbG9nIikgfiAiSStJZyBsb2ciLAogICAgbGFiZWwgPT0gIlIiIH4gIlIiLAogICAgbGFiZWwgPT0gIlIgbG9nIiB+ICJSIGxvZyIsCiAgICBsYWJlbCAlaW4lIGMoIkciLCAiRzErRzIiKSB+ICJHIiwKICAgIGxhYmVsID09ICJHIGxvZyIgfiAiRyBsb2ciCiAgKSkgCgojIGdldCBsaW1pdCBmb3Igc2lfcnVnCnNpX3J1Z19saW0uZGYgPC0gc2lfcnVnLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCkgJT4lCiAgZ3JvdXBfYnkobGFiZWwpJT4lIAogIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUsIG5hLnJtID0gVCkqMC45LAogICAgICAgICBtYXggPSBtYXgodmFsdWUsIG5hLnJtID0gVCkqMS4xKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpID0gbGFiZWwsIG1pbl9zaSA9IG1pbiwgbWF4X3NpID0gbWF4KQoKIyBmaWx0ZXIgdG8gcmVzdHJpY3Rpb24gY29udmVyc2lvbiByYXRlIHJlYWN0aW9uIG5vcm0gcmFuZ2UgdG8gY3VlIHJhbmdlcyB0aGF0IGFwcGVhciBpbiBydWcKIyMgY2hhbmdlIHRvIEluZi8taW5mIHRvIE5BLiBOb3RlIHRoYXQgSSBhbSBmaXJzdCBqb2luaW5nIHdpdGggc2kgcnVnIGxpbSB0byBjaGVjayB3aGljaCBsaW1pdCBpcyBsYXJnZXIsIFdlIHdpbGwgZ28gd2l0aCB0aGUgY3VlIHJhbmdlIHRoYXQgaGFzIHRoZSBsYXJnZXN0IHNwYW4KY2lfcnVnX2xpbS5kZiA8LSBzaV9jaV9ydWcuZGYgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgbXV0YXRlKG1pbiA9IG1pbih2YWx1ZSwgbmEucm0gPSBUKSowLjksCiAgICAgICAgIG1heCA9IG1heCh2YWx1ZSwgbmEucm0gPSBUKSoxLjEpICU+JSAKICBkaXN0aW5jdChsYWJlbCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIHNlbGVjdChsYWJlbCwgbGFiZWxfc2ksIG1pbiwgbWF4KQoKcnVnX2xpbS5maW5hbCA8LSBjaV9ydWdfbGltLmRmICU+JSBsZWZ0X2pvaW4oc2lfcnVnX2xpbS5kZiwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgbXV0YXRlKGZpbmFsX21pbiA9IG1pbihtaW4sIG1pbl9zaSksCiAgICAgICAgIGZpbmFsX21heCA9IG1heChtYXgsIG1heF9zaSkpCgojIGdldCBzZWNvbmQgcnVnX2xpbS5maW5hbCBmb3Igc2luZ2xlIGluZmVjdGlvbgpydWdfbGltLmZpbmFsMiA8LSBydWdfbGltLmZpbmFsICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIG11dGF0ZShmaW5hbF9taW4gPSBtaW4oZmluYWxfbWluLCBuYS5ybSA9IFQpLAogICAgICAgICBmaW5hbF9tYXggPSBtYXgoZmluYWxfbWF4LCBuYS5ybSA9IFQpKQoKIyBmaWx0ZXIgY2lfcm4gYnkgbGltaXQKY2lfcm4uZGYyIDwtIGNpX3JuLmRmICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbS5maW5hbCwgYnkgID0gImxhYmVsIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBmaW5hbF9tYXggJiBjdWVfcmFuZ2UgPj0gZmluYWxfbWluKSAlPiUgCiAgYXJyYW5nZShjdWVfcmFuZ2UsIC5ieV9ncm91cCA9IFQpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09IDApIApgYGAKCiMgbWF0Y2ggc2luZ2xlIGluZmVjdGlvbiBybiB3aXRoIGNvaW5mZWN0aW9uIApgYGB7cn0KIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnIGFuZCBmaWx0ZXIgYnkgbGltaXQKc2lfcm4uZGYyIDwtIGxlZnRfam9pbihzaV9ybi5kZiwgc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9zaSwgbGFiZWxfY2kpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9zaSIpKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0uZmluYWwsIGJ5ICA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbCIpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IGZpbmFsX21heCAmIGN1ZV9yYW5nZSA+PSBmaW5hbF9taW4pICU+JSAKICBhcnJhbmdlKGN1ZV9yYW5nZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0gMCkgJT4lIAogIHNlbGVjdChjdWVfcmFuZ2UsIGNyLCBsYWJlbF9jaSwgbGFiZWxfc2kpCgojIGdldCBjaSBsYWJlbCB0byBzaSBydWcsIHdlIHdpbGwga2VlcCBvbmUgdW5pcXVlIHZhbHVlIHBlciBsYWJlbApzaV9ydWcuZGYyIDwtIHNlbGVjdChzaV9ydWcuZGYsIHZhbHVlLCBsYWJlbF9zaSA9IGxhYmVsKSAlPiUgZGlzdGluY3QodmFsdWUsIGxhYmVsX3NpKQpgYGAKCiMgcGxvdCByZWFjdGlvbiBub3JtCmBgYHtyfQojIGpvaW4gd2l0aCBlemxhYmVsCmNpX3JuLmRmMyA8LSBjaV9ybi5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKc2lfcm4uZGYzIDwtIHNpX3JuLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9jaSIpCmNpX3J1Zy5kZjMgPC0gY2lfcnVnLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCnNpX3J1Zy5kZjMgPC0gc2lfcnVnLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCmBgYAoKCmBgYHtyfQojIHJlZG8gb3JkZXIgb2YgY3VlcwpjaV9ybi5kZjMkZXpfbGFiZWwgPC0gZmFjdG9yKGNpX3JuLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpIAoKc2lfcm4uZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ybi5kZjMkZXpfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJBc2V4dWFsIGlSQkMiLCAiQXNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgYXNleHVhbCBpUkJDIiwgIlRvdGFsIGFzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXh1YWwgaVJCQyIsICJTZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzZXh1YWwmc2V4dWFsIGlSQkMiLCAiQXNleHVhbCZzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBpUkJDIiwgIlRvdGFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW1ldG9jeXRlIiwgIkdhbWV0b2N5dGUgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBnYW1ldG9jeXRlIiwgIlRvdGFsIHNleHVhbCBpUkJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUkJDIiwgIlJCQyBsb2cxMCIpKQoKY2lfcnVnLmRmMyRlel9sYWJlbCA8LSBmYWN0b3IoY2lfcnVnLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpCgpzaV9ydWcuZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ydWcuZGYzJGV6X2xhYmVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQXNleHVhbCBpUkJDIiwgIkFzZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGFzZXh1YWwgaVJCQyIsICJUb3RhbCBhc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2V4dWFsIGlSQkMiLCAiU2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2V4dWFsJnNleHVhbCBpUkJDIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgaVJCQyIsICJUb3RhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2FtZXRvY3l0ZSIsICJHYW1ldG9jeXRlIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgZ2FtZXRvY3l0ZSIsICJUb3RhbCBzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJCQyIsICJSQkMgbG9nMTAiKSkKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGNpX3JuLmRmMywgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIikpICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9ybi5kZjMgJT4lIAogICAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICAgIG11dGF0ZSh0ZW5fdGggPSByb3VuZChuKCkvMTApKSAlPiUgCiAgICBmaWx0ZXIocm93X251bWJlcigpICUlIHRlbl90aCA9PSAwKSwgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIiwgc2hhcGUgPSAiQ28taW5mZWN0aW9uIiksIHNpemUgPSAyKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9ybi5kZjMsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb24iKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNpX3JuLmRmMyAlPiUgCiAgICBncm91cF9ieShsYWJlbF9jaSkgJT4lIAogICAgbXV0YXRlKHRlbl90aCA9IHJvdW5kKG4oKS8xMCkpICU+JSAKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgdGVuX3RoID09IDApLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uIiwgc2hhcGUgPSAiU2luZ2xlIGluZmVjdGlvbiIpLCBzaXplID0gMikgKwogIGdlb21fcnVnKGRhdGEgPSBjaV9ydWcuZGYzLCBhZXMoeCA9IHZhbHVlKSwgY29sb3IgPSAiIzQ1NzViNCIsIHNpZGVzID0gInQiLCBsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpKSArCiAgZ2VvbV9ydWcoZGF0YSA9IHNpX3J1Zy5kZjMsIGFlcyh4ID0gdmFsdWUpLCBjb2xvciA9ICIjZmM4ZDU5Iiwgc2lkZXMgPSAiYiIsIGxlbmd0aCA9IHVuaXQoMC4xLCAibnBjIikpICsKICBmYWNldF93cmFwKH5lel9sYWJlbCwgc2NhbGVzID0gImZyZWVfeCIsIG5jb2wgPSAyKSArCiAgeWxpbSgtMC4zLCAxLjMpICsKICB0aGVtZV9idygpICsKICBsYWJzKHkgPSAiQ29udmVyc2lvbiByYXRlIiwgeCA9ICJDdWUgcmFuZ2UiLCBjb2xvciA9ICJNb2RlbCIsIHNoYXBlID0gIk1vZGVsIikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFQpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoY2hlY2sub3ZlcmxhcCA9IFRSVUUpKSArIAogICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIpKSArCiAgdGhlbWUoc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihiID0gMC41LCB0ID0gMC41KSkpCgpnZ3NhdmUodW5pdHMgPSAicHgiLCBkcGkgPSAzMDAsIHdpZHRoID0gMjAwMCwgaGVpZ2h0ID0gMjUwMCwgZmlsZW5hbWUgPSBoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3JlYWN0aW9uX25vcm0udGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS4xKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKUGxvdHRpbmcgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gZml0bmVzcyBzY2F0dGVyIHBsb3QKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGltcG9ydCBpbiBkYXRhCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzCmNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfZHluLnBhcnF1ZXQiKSkKCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCmBgYAoKIyBwcm9jZXNzIGZvciBmaW5hbCAyMCBkYXlzIGZpdG5lc3MKYGBge3J9CiMgZ2V0IHNpbmdsZSBpbmZlY3Rpb24gbWF4aW11bSB0YXVfY3VtIGZvciAyMCBkYXlzCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgZ2V0IGNvLWluZmVjdGlvbiBtYXhpbXVtIHRhdV9jdW0gZm9yIDIwIGRheXMKY2lfZml0bmVzcy5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bTEiICYgdGltZSA9PSAyMCkKCiMgam9pbiB0b2dldGhlciB0d28gZGF0YWZyYW1lcyBhbmQgYWRkIGxhYmVscwpzaV9jaV9maXRuZXNzLmRmIDwtIHNlbGVjdChjaV9maXRuZXNzLmRmLCBmaXRuZXNzX2NpID0gdmFsdWUsIGxhYmVsX2NpID0gbGFiZWwpICU+JSAKICBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX2NpIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgZml0bmVzc19zaSA9IHZhbHVlLCBpZF9zaSA9IGlkKSwgYnkgPSAiaWRfc2kiKSAlPiUgCiAgc2VsZWN0KGV6X2xhYmVsX3NpLCBlel9sYWJlbCwgZml0bmVzc19zaSwgZml0bmVzc19jaSkgJT4lIAogIHJiaW5kKGRhdGEuZnJhbWUoICMgYWRkIHRpbWUKICAgIGV6X2xhYmVsX3NpID0gIlRpbWUiLCAKICAgIGV6X2xhYmVsID0gIlRpbWUiLAogICAgZml0bmVzc19zaSA9ICA5Ljc4Nzg5OSwKICAgIGZpdG5lc3NfY2kgID0gMi4zMTE4NDEKICApKQoKc2lfY2lfZml0bmVzcy5kZgpgYGAKCiMgcGxvdCBzY2F0dGVyIHBvaW50IG9mIHNpbmdsZSBpbmZlY3Rpb24gdnMgY28taW5mZWN0aW9uCmBgYHtyfQpzaV9jaV9maXRuZXNzLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9jaV9maXRuZXNzLmRmLCBhZXMoeCA9IGZpdG5lc3Nfc2ksIHkgPSBmaXRuZXNzX2NpLCBjb2xvciA9IGV6X2xhYmVsX3NpLCBzaGFwZSA9IGV6X2xhYmVsX3NpKSwgc2l6ZSA9IDMuNSkgKwogIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IHNpX2NpX2ZpdG5lc3MuZGYsIGFlcyhsYWJlbCA9IGV6X2xhYmVsLCB4ID0gZml0bmVzc19zaSwgeSA9IGZpdG5lc3NfY2kpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIseGxpbSA9IGMoLUluZiwgSW5mKSwgeWxpbSA9IGMoTkEsIE5BKSkgKwogIGxhYnMoeCA9ICJNYXhpbXVtIHNpbmdsZSBpbmZlY3Rpb24gZml0bmVzcyIsIHkgPSAiTWF4aW11bSBDby1pbmZlY3Rpb24gZml0bmVzcyAocGVyIHN0cmFpbikiLAogICAgICAgY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWUiLCBzaGFwZSA9ICJTaW5nbGUgaW5mZWN0aW9uIGN1ZSIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTU6MjUpICsKICBsaW1zKHggPSBjKDgsIDEwLjMpKSArCiAgdGhlbWVfYncoKQpgYGAKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyB0aW1lIHNlcmllcyBjb252ZXJzaW9uIHJhdGUgZm9yIHNpbmdsZSBhbmQgY28taW5mZWN0aW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tLS1nZXQgImlkZWFsIiBzaW5nbGUgaW5mZWN0aW9uIGFuZCBjby1pbmZlY3Rpb24gZHluYW1pY3MtLS0tLS0tLS0jClRoaXMgaXMgd2hlbiBzdHVmZiBhcmUgb3B0aW1pemVkIGJhc2VkIG9uIHRpbWUKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW4uUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX2NpX2NsZWFuLlIiKSkKCiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljIHdpdGggdGltZSBhcyBjdWUuIE9wdGltaXplZCB1c2luZyBsb2NhbCBvcHRpbWl6ZXIuIE5vdGUgdGhhdCB0aGUgdGltZSB2YXJpYWJsZSBpbiBkdWFsIGN1ZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgd2l0aCBoaWdoZXIgZmxleGliaWxpdHkuIFdoaWxlIHRoYXQgaW5jcmVhc2VzIHRoZSBmaXRuZXNzIHZhbHVlIGJ5IH4wLjEsIHRoZSBvdmVyYWxsIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIGRvZXMgbm90IGNoYW5nZSB0aGF0IG11Y2gKc2lfdC5kZiA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjU1Mzg2LCAtMTMuMDA1NiwgNC4xNTQ2NiwgLTExLjk0MjQpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlID0gInQiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pYyB3aXRoIHRpbWUgYXMgY3VlCmNpX3QuZGYgPC0gY2hhYmF1ZGlfY2lfY2xlYW4ocGFyYW1ldGVyc19jcl8xID0gYygyNi4xNjQyNSwJLTcxLjA3Nzk5LAk1My4zNDEyMSwJLTE2Ni4yNTY5MyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzX2NyXzIgPSBjKDI2LjE2NDI1LAktNzEuMDc3OTksCTUzLjM0MTIxLAktMTY2LjI1NjkzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9yYW5nZSA9IHRpbWVfcmFuZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzEgPSAgInQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzI9ICJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8xID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8yID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMSA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMiA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbHZlciA9ICJ2b2RlIiwgIyBzb2x2ZXIgZm9yIG51bWVyaWNhbCBpbnRlZ3JhdGlvbi4gVm9kZSBvZnRlbiBnaXZlcyBmYXN0ZXIgcnVucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkeW4gPSBUKQoKIyBnZXQgb25seSBjb252ZXJzaW9uIHJhdGUgYW5kIG1ha2Ugc2FtZSBmb3JtYXQgYXMgc2lfY3IuZGYyL2NpX2NyLmRmMgpzaV90LmRmICU+JSBmaWx0ZXIodGltZSA9PSAyMCAmIHZhcmlhYmxlID09ICJ0YXVfY3VtIikgIyMgZml0bmVzcyB2YWx1ZSBvZiB0aW1lIGFzIGN1ZSBpbiBzaW5nbGUgaW5mZWN0aW9uCnNpX3QuY3IgPC0gc2lfdC5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWxfc2kgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX3NpID05Ljc4Nzg5OSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpCgoKIyMgZ2V0IGZpdG5lc3MgdmFsdWUgb2YgY28taW5mZWN0aW9uIHRpbWUKY2lfdC5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtMSIpICU+JSBzdW1tYXJpemUobWF4ID0gbWF4KHZhbHVlLCBuYS5ybSA9IFQpKQpjaV90LmNyIDwtIGNpX3QuZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiY3JfMSIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWwgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX2NpID0gMi4zMTE4NDEsCiAgICAgICAgIGxhYmVsID0gIlRpbWUiKSAlPiUKICBzZWxlY3QodGltZSwgdmFsdWUsIGZpdG5lc3NfY2ksIGV6X2xhYmVsLCBsYWJlbCkKYGBgCgojLS0tLS0tLS0tIHNpbmdsZSBpbmZlY3Rpb24gY29udmVyc2lvbiByYXRlIGhlYXQgbWFwLS0tLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBpbmZvIGZvciBzaW5nbGUgaW5mZWN0aW9uCmBgYHtyfQojIGdldCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKc2lfY3IuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCAmIHZhcmlhYmxlID09ICJjciIpCgojIGdldCB0aW1lIHJhbmdlcy4gV2Ugd2lsbCBvbWl0IGFueSB2YWx1ZXMgd2hlcmUgSSBpcyBiZWxvdyAxMDAuIE5vdGUgZm9yIGFsbCBzaW5nbGUgaW5mZWN0aW9uLCBpdCBpcyBmb3JtICAwLjU1IHRvIDIwLiBOb3RlIHdlIGFyZSBub3QgZG9pbmcgSStJZyBiZWNhdXNlIGNvbnZlcnNpb24gcmF0ZSBpcyBvbmx5IHJlbGV2ZW50IHdoZW4gYXNleHVhbCBpUkJDIGlzIGFyb3VuZCB0byBkaWZmZXJlbnRpYXRlIQpzaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkiICYgdmFsdWUgPiAxMDApICU+JQogIGdyb3VwX2J5KGlkKSAlPiUgCiAgc3VtbWFyaXplKG1pbl90aW1lID0gbWluKHRpbWUpLAogICAgICAgICAgICBtYXhfdGltZSA9IG1heCh0aW1lKSkKCiMgam9pbiBmaXRuZXNzIGFuZCBpZGVhbCBkeW5hbWljcwpzaV9jci5kZjIgPC0gc2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3Nfc2kgPSB2YWx1ZSksIGJ5ID0gImlkIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpICU+JSAKICByYmluZChzaV90LmNyKSAjIGpvaW4gd2l0aCBkYXRhZnJhbWUgY29udGFpbmluZyBpZGVhbCBkeW5hbWljcwoKIyBwbG90LiBub3RlIHRoYXQgd2UgYXJlIG9taXR0aW5nIGRheSAxIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIGJlY2F1c2UgYWxsIGNyIGF0IHRoYXQgc3RhZ2UgaXMgMCAoYnkgbW9kZWwgZGVmYXVsdCkKc2lfY3IucGwgPC0gZ2dwbG90KGRhdGEgPSBzaV9jci5kZjIsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsX3NpLCBmaXRuZXNzX3NpKSkpICsKICBnZW9tX3Jhc3RlcihhZXMoZmlsbCA9IHZhbHVlKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKGxpbWl0cyA9IGMoMCwgMSksIG9vYiA9IHNjYWxlczo6c3F1aXNoKSArCiAgeGxpbSgxLCAyMCkgKwogIHRoZW1lX2J3KCkKYGBgCgojIC0tLS0tLS0tLS0tLS0tLS0tY28taW5mZWN0aW9uIGNvbnZlcnNpb24gcmF0ZSBoZWF0bWFwLS0tLS0tLS0tLS0jCiMgcGxvdCBjby1pbmZlY2l0b24gY29udmVzaW9uIHJhdGUgaGVhdG1hcApgYGB7cn0KIyBnZXQgY29udmVyc2lvbiByYXRlIGR5bmFtaWNzCmNpX2NyLmRmIDwtIGNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHRpbWUgPD0gMjAgJiB2YXJpYWJsZSA9PSAiY3JfMSIpCgojIGdldCB0aW1lIHJhbmdlIHRvIGluY2x1ZGUuIFNhbWUgY3JpdGVyaWEuIHdlIG5lZWQgaWYgc2luZ2xlIHN0cmFpbiBwb3B1bGF0aW9uIGRlY2xpbmVzIHRvIGxlc3MgdGhhbiAxMDAKIyMgd2hlbiB0aW1lIGlzIHVzZWQgYXMgYSBjdWU6IDEyLjk0MwpjaV90LmRmICU+JQogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkxIiAmIHZhbHVlID4gMTAwKSAlPiUgCiAgc3VtbWFyaXplKG1heF90aW1lID0gbWF4KHRpbWUpKQojIyBhbGwgb3RoZXIgZHluYW1pY3MKY2lfY3IudGltZSA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkxIiAmIHZhbHVlID4gMTAwKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICBzdW1tYXJpemUobWF4X3RpbWUgPSBtYXgodGltZSkpICU+JSAKICByYmluZChkYXRhLmZyYW1lKGxhYmVsID0gIlRpbWUiLCBtYXhfdGltZSA9IDEyLjk0MykpCgojIGpvaW4gd2l0aCBmaXRuZXNzLCBpZGVhbCBkeW5hbWljcyBhbmQgYWxzbyBtYXhpbXVtIHRpbWUgcmFuZ2UgY29uc2lkZXJlZApjaV9jci5kZjIgPC0gY2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfZml0bmVzcy5kZiwgbGFiZWwsIGZpdG5lc3NfY2kgPSB2YWx1ZSksIGJ5ID0gImxhYmVsIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19jaSwgZXpfbGFiZWwsIGxhYmVsKSAlPiUgCiAgcmJpbmQoY2lfdC5jcikgJT4lICMgYmluZCBpZGVhbCBkeW5hbWljcwogIGxlZnRfam9pbihjaV9jci50aW1lLCBieSA9ICJsYWJlbCIpICU+JSAKICBmaWx0ZXIodGltZSA8PSBtYXhfdGltZSkgIyBrZWVwIG9ubHkgdGhvc2UgdGhhdCBhcmUgd2l0aGluIHRpbWUgcmFuZ2UKCiMgcGxvdApjaV9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IGNpX2NyLmRmMiwgCiAgICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZXpfbGFiZWwsIGZpdG5lc3NfY2kpLCBmaWxsID0gdmFsdWUpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDby1pbmZlY3Rpb24gY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcyhsaW1pdHMgPSBjKDAsIDEpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCmBgYAoKIy0tLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGNvbWJpbmUgY29udmVyc2lvbiByYXRlIGR5bmFtaWMgb2Ygc2luZ2xlIGluZmVjdGlvbiBhbmQgY28taW5mZWN0aW9uCmNyLnBsIDwtIGdnYXJyYW5nZShzaV9jci5wbCwgY2lfY3IucGwsIGxhYmVscyA9IGMoIkIiLCAiQyIpLCBuY29sID0gMiwgY29tbW9uLmxlZ2VuZCA9IFQsIGFsaWduID0gImgiKQoKIyBjb21iaW5lIHdpdGggZml0bmVzcyBzY2F0dGVycGxvdApnZ2FycmFuZ2Uoc2lfY2lfZml0bmVzcy5wbCwgY3IucGwsIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJBIiwgIiIpLCBhbGlnbiA9ICJodiIpCgojIHNhdmUKZ2dzYXZlKHVuaXRzID0gInB4IiwgZHBpID0gMzAwLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDIwMDAsIGZpbGVuYW1lID0gaGVyZSgiZmlndXJlcy9wbG9zLWJpby9maXRuZXNzX2NyLWR5bi50aWZmIiksIGJnID0gIndoaXRlIiwgc2NhbGUgPSAxLjM1KQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBEZW1vZ3JhcGhpYyBzdG9jaGFzdGljaXR5CiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIy0tLS0tLS0tLS0gcGxvdCBoZWF0IG1hcC0tLS0tLS0tLS0tLS0tLSMKIyBpbXBvcnQgaW4gYWxsIGZpdG5lc3MgZmlsZXMKYGBge3J9CmZpbGVfbHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9NQ19wYXJ0aXRpb25lZC8iKSwgcGF0dGVybiA9ICIqLmNzdiIsIGZ1bGwubmFtZXMgPSBUKQpuYW1lX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUNfcGFydGl0aW9uZWQvIiksIHBhdHRlcm4gPSAiKi5jc3YiKQpuYW1lX2xzIDwtIGdzdWIoIiouY3N2IiwgIiIsIG5hbWVfbHMpCgojIDYwLCB3aGljaCBpcyBhYm91dCByaWdodApsZW5ndGgoZmlsZV9scykKCiMgcmVhZCBpbiBmaWxlcwpmaXRuZXNzLmxzIDwtIGxhcHBseShmaWxlX2xzLCByZWFkLmNzdikKCiMgYXNzaWduIHVuaXF1ZSBJRApmaXRuZXNzLmxzIDwtIG1hcHBseShjYmluZCwgZml0bmVzcy5scywgIklEIiA9IG5hbWVfbHMsIFNJTVBMSUZZID0gRikKYGBgCgojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBnZXQgbWV0YWluZm8gZnJvbSBJRApmaXRuZXNzLmxzMiA8LSBtY2xhcHBseShmaXRuZXNzLmxzLCBmdW5jdGlvbih4KXsKICBpZF9jb2wgPC0geCRJRAogICMgc3RyaW5nIHNwbGl0IHRvIGV4dHJhY3QgYWxsIGluZm8KICBjdWUgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1szXV0KICBsb2cgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1s0XV0KICByYW5kX3ZhciA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzVdXQogIAogICMgZ2V0IG1lYW4KICBtZWFuX2ZpdG5lc3MgPC0gbWVhbih4JG1heF9maXRuZXNzKQogICMgZ2V0IHNkCiAgc2RfZml0bmVzcyA8LSBzZCh4JG1heF9maXRuZXNzKQogIAogICMgYmluZCByZXN1bHRzCiAgcmVzIDwtIGNiaW5kKHgsIGN1ZT0gY3VlLCBsb2cgPSBsb2csIHJhbmRfdmFyID0gcmFuZF92YXIsIG1lYW5fZml0bmVzcyA9IG1lYW5fZml0bmVzcywgc2RfZml0bmVzcyA9IHNkX2ZpdG5lc3MpCiAgcmV0dXJuKHJlcykKfSkKYGBgCgojIEdldCByZWZlcmVuY2UgZGF0YQpgYGB7cn0KcmVmZXJlbmNlX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUMyIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKcmVmZXJlbmNlX25hbWUubHMgPC0gZ3N1YigiKi5jc3YiLCAiIiwgbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9NQzIvIiksIHBhdHRlcm4gPSAiKi5jc3YiKSkKCiMgcmVhZCBpbiB0aGUgZmlsZXMKcmVmZXJlbmNlLmxzIDwtIGxhcHBseShyZWZlcmVuY2VfbHMsIHJlYWQuY3N2KQoKIyBhc3NpZ24gdW5pcXVlIElECnJlZmVyZW5jZS5scyA8LSBtYXBwbHkoY2JpbmQsIHJlZmVyZW5jZS5scywgIklEIiA9IHJlZmVyZW5jZV9uYW1lLmxzLCBTSU1QTElGWSA9IEYpCgojIGdldCBtZXRhIGRhdGEKcmVmZXJlbmNlLmxzMiA8LSBtY2xhcHBseShyZWZlcmVuY2UubHMsIGZ1bmN0aW9uKHgpewogIGlkX2NvbCA8LSB4JElECiAgIyBzdHJpbmcgc3BsaXQgdG8gZXh0cmFjdCBhbGwgaW5mbwogIGN1ZSA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzJdXQogICMgZ2V0IGxvZwogIHRoaXJkX2NvbCA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzNdXQogIGxvZyA8LSBpZmVsc2UodGhpcmRfY29sID09ICJsb2ciLCAibG9nMTAiLCAibm9uZSIpCiAgCiAgIyBnZXQgbWVhbgogIG1lYW5fZml0bmVzcyA8LSBtZWFuKHgkbWF4X2ZpdG5lc3MpCiAgCiAgIyBnZXQgc2QKICBzZF9maXRuZXNzIDwtIHNkKHgkbWF4X2ZpdG5lc3MpCiAgCiAgIyBiaW5kIHJlc3VsdHMKICByZXMgPC0gY2JpbmQoeCwgY3VlPSBjdWUsIGxvZyA9IGxvZywgcmFuZF92YXIgPSAiYWxsIiwgcmVmX21lYW5fZml0bmVzcyA9IG1lYW5fZml0bmVzcywgcmVmX3NkX2ZpdG5lc3MgPSBzZF9maXRuZXNzKQogIHJldHVybihyZXMpCn0pCmBgYAoKIyBjb21iaW5lIE1DIHBhcnRpdGlvbmVkIGFuZCByZWZlcmVuY2UgZGYKYGBge3J9CiMgZ2V0IHVuaXF1ZSBjb2x1bW4gdmFsdWVzIGZvciBlYWNoIGN1ZSwgbG9nLCBhbmQgcmFuZF92YXIgY29tYm8KZml0bmVzcy5sczMgPC0gZG8uY2FsbChyYmluZCwgZml0bmVzcy5sczIpCmZpdG5lc3MubHMzIDwtIGZpdG5lc3MubHMzICU+JSBkcGx5cjo6ZGlzdGluY3QoSUQsIC5rZWVwX2FsbCA9IFQpCgojIHJlcGVhdCB3aXRoIHJlZmVyZW5jZQpyZWZlcmVuY2UubHMzIDwtIGRvLmNhbGwocmJpbmQsIHJlZmVyZW5jZS5sczIpCnJlZmVyZW5jZS5sczMgPC0gcmVmZXJlbmNlLmxzMyAlPiUgZHBseXI6OmRpc3RpbmN0KElELCAua2VlcF9hbGwgPSBUKQoKIyBjb21iaW5lIQpyZWZfZml0LmRmIDwtIGxlZnRfam9pbihmaXRuZXNzLmxzMywgcmVmZXJlbmNlLmxzMywgYnkgPSBjKCJjdWUiID0gImN1ZSIsICJsb2ciPSAibG9nIikpCmBgYAoKIyBjb21wdXRlIHByb3BvcnRpb24gZml0bmVzcyBhbmQgdmFyaWF0aW9uCmBgYHtyfQpyZWZfZml0LmRmMiA8LSByZWZfZml0LmRmICU+JSAKICBtdXRhdGUocF9zZCA9IHNkX2ZpdG5lc3MvcmVmX3NkX2ZpdG5lc3MsCiAgICAgICAgIHBfbWVhbiA9IHJlZl9tZWFuX2ZpdG5lc3MvbWVhbl9maXRuZXNzLAogICAgICAgICBjdWVfbG9nID0gcGFzdGUwKGN1ZSwgIl8iLCBsb2cpLAogICAgICAgICBsYWJlbCA9IGNhc2Vfd2hlbigKICAgICAgICAgICBjdWUgPT0gIkciIH4gIkdhbWV0b2N5dGUiLAogICAgICAgICAgIGN1ZSA9PSAiSSIgfiAiQXNleHVhbCBpUkJDIiwKICAgICAgICAgICBjdWUgPT0gIkkrSWciIH4gIkFzZXh1YWwmc2V4dWFsXG5pUkJDIiwKICAgICAgICAgICBjdWUgPT0gIklnIiB+ICJTZXh1YWwgaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJSIiB+ICJSQkMiCiAgICAgICAgICAgKSwKICAgICAgICAgcGFyYW1ldGVyID0gY2FzZV93aGVuKAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInJobyIgfiAiUkJDIHJlcGxlbmlzaG1lbnQgKM+BKSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicGhpbiIgfiAiSGFsZi1saWZlIGluZGlzICjPlW4pIiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwaGl3In4gIkhhbGYtbGlmZSB0YXJnZXRlZCAoz5V3KSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicHNpbiIgfiAiQWN0aXZhdGlvbiBpbmRpcyAoz4huKSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicHNpdyIgfiAiQWN0aXZhdGlvbiB0YXJnZXRlZCAoz4h3KSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAiYmV0YSIgfiAiQnVyc3Qgc2l6ZSAozrIpIgogICAgICAgICApKQpgYGAKCiMgcGxvdCEKYGBge3J9CiMgdmFyaWF0aW9uCm1jX2IgPC0gZ2dwbG90KCkgKwogIGdlb21fdGlsZShkYXRhID0gcmVmX2ZpdC5kZjIgLCBhZXMoeCA9IGxhYmVsLCB5ID0gcGFyYW1ldGVyLCBmaWxsID0gcF9zZCkpICsKICBmYWNldF93cmFwKH5sb2cpICsKICB0aGVtZV9idygpICsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoKSArCiAgbGFicyh4ID0gIkN1ZSIsIHkgPSAiUGFyYW1ldGVyIHJhbmRvbWl6ZWQiLCBmaWxsID0gZXhwcmVzc2lvbihmcmFjKHNkKCIxIHBhcmFtZXRlciByYW5kb21pemVkIiksIHNkKCJhbGwgcGFyYW1ldGVycyByYW5kb21pemVkIikpKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKCiMgbWVhbiBmaXRuZXNzCm1jX2MgPC0gZ2dwbG90KCkgKwogIGdlb21fdGlsZShkYXRhID0gcmVmX2ZpdC5kZjIgLCBhZXMoeCA9IGxhYmVsLCB5ID0gcGFyYW1ldGVyLCBmaWxsID0gcF9tZWFuKSkgKwogIGZhY2V0X3dyYXAofmxvZykgKwogIHRoZW1lX2J3KCkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBsYWJzKHggPSAiQ3VlIiwgeSA9ICJQYXJhbWV0ZXIgcmFuZG9taXplZCIsIGZpbGwgPSBleHByZXNzaW9uKGZyYWMoTWVhbigiYWxsIHBhcmFtZXRlcnMgcmFuZG9taXplZCIpLCBNZWFuKCIxIHBhcmFtZXRlciByYW5kb21pemVkIikpKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKCm1jX3BhcnRpdGlvbiA8LSBnZ2FycmFuZ2UobWNfYiwgbWNfYywgbmNvbCA9IDEpCgpgYGAKCiMtLS0tLS0tLS0tLS0tLSBnZXQgdmlvbGluZSBwbG90IG9mIHZhcmlhdGlvbiBpbiBmaXRuZXNzIC0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIHJlYWQgTUMgZGF0YQpgYGB7cn0KIyByZWFkIGluIGR5bWFtaWNzCm1jX0dfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfR19sb2dfZHluLnBhcnF1ZXQiKSkKbWNfRy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0dfZHluLnBhcnF1ZXQiKSkKbWNfUl9sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19SX2xvZ19keW4ucGFycXVldCIpKQptY19SLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfUl9keW4ucGFycXVldCIpKQptY19JX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lfbG9nX2R5bi5wYXJxdWV0IikpCm1jX0kuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19JX2R5bi5wYXJxdWV0IikpCm1jX0lnX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lnX2xvZ19keW4ucGFycXVldCIpKQptY19JZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lnX2R5bi5wYXJxdWV0IikpCm1jX0lfSWdfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19sb2dfZHluLnBhcnF1ZXQiKSkKbWNfSV9JZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0krSWdfZHluLnBhcnF1ZXQiKSkKCiMgcmVhZCBpbiBmaXRuZXNzCm1jX0dfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfR19sb2dfZml0bmVzcy5jc3YiKSkKbWNfRy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0dfZml0bmVzcy5jc3YiKSkKbWNfUl9sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19SX2xvZ19maXRuZXNzLmNzdiIpKQptY19SLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfUl9maXRuZXNzLmNzdiIpKQptY19JX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX0kuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19JX2ZpdG5lc3MuY3N2IikpCm1jX0lnX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lnX2xvZ19maXRuZXNzLmNzdiIpKQptY19JZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lnX2ZpdG5lc3MuY3N2IikpCm1jX0lfSWdfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19sb2dfZml0bmVzcy5jc3YiKSkKbWNfSV9JZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0krSWdfZml0bmVzcy5jc3YiKSkKYGBgCgojIGV4YW1pbmUgdmFyaWF0aW9uCmBgYHtyfQojIHBsb3QgZml0bmVzcyB2cyBpdGVyYXRpb24KZml0bmVzcy5kZiA8LSByYmluZCgKICBjYmluZChtY19HX2xvZy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIGxvZzEwIiksCiAgY2JpbmQobWNfRy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIiksCiAgY2JpbmQobWNfUl9sb2cuZml0bmVzcywgaWQgPSAiUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfUi5maXRuZXNzLCBpZCA9ICJSQkMiKSwKICBjYmluZChtY19JX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiKSwKICBjYmluZChtY19JLmZpdG5lc3MsIGlkID0gIkFzZXh1YWwgaVJCQyIpLAogIGNiaW5kKG1jX0lnX2xvZy5maXRuZXNzLCBpZCA9ICJTZXh1YWwgaVJCQyBsb2cxMCIpLAogIGNiaW5kKG1jX0lnLmZpdG5lc3MsIGlkID0gIlNleHVhbCBpUkJDIiksCiAgY2JpbmQobWNfSV9JZ19sb2cuZml0bmVzcywgaWQgPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfSV9JZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiKQopCgojIHF1YW50aWZ5IHZhcmlhbmNlIGFuZCBtZWFuCmZpdG5lc3NfdmFyLmRmIDwtIGZpdG5lc3MuZGYgJT4lIAogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKG1heF9maXRuZXNzKSwKICAgICAgICAgICAgICAgICAgIG1lYW4gPSBtZWFuKG1heF9maXRuZXNzKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoaWQgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihpZCwgbWVkaWFuKSkKYGBgCgojIHBsb3QgdmlvbGluIHdpdGggZGlmZmVyZW5jZSBpbiBkZXRlcm1pbmlzdGljIG1vZGVsIGZpdG5lc3MgYW5kIG1lYW4gbW9kZWwgZml0bmVzcwpgYGB7cn0KIyBnZXQgZGV0ZXJtaW5pc3RpYyBkZgpkZXQuZGYgPC0gZGF0YS5mcmFtZShmaXRuZXNzX3Zhci5kZiwgYE1heGltdW0gZml0bmVzc2AgPSAgYyg4LjQ5Nzc3LCA5LjQ5NDk5MSw4Ljg1NDY4Miw5LjU3MzI5MSw4LjU4ODU2LDkuNTYxMzczLDguMjM5OTEsOC4xODE2MDQsOC41NjkyODUsOS42MTg4MTIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShpZCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGlkLCBtZWRpYW4pKSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcigtaWQpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBjYXNlX3doZW4oCiAgICBuYW1lID09ICJNYXhpbXVtLmZpdG5lc3MiIH4iT3B0aW1hbCBzaW5nbGUgaW5mZWN0aW9uIiwKICAgIG5hbWUgPT0gIm1lZGlhbiIgfiJNZWRpYW4gTW9udGUgQ2FybG8iLAogICAgbmFtZSA9PSAibWVhbiIgfiAiTWVhbiBNb250ZSBDYXJsbyIpKQoKbWNfYSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGV0LmRmLCBhZXMoeSA9IGlkLCB4ID0gdmFsdWUsIHNoYXBlID0gY2xhc3NpZmljYXRpb24sIGNvbG9yID0gY2xhc3NpZmljYXRpb24pLCBzaXplID0gMywgYWxwaGEgPSAwLjgpICsKICBnZW9tX3Zpb2xpbihkYXRhID0gZml0bmVzcy5kZiwgYWVzKHkgPSBpZCwgeCA9IG1heF9maXRuZXNzKSwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ3VlIiwgY29sb3IgPSAiRml0bmVzcyIsIHNoYXBlID0gIkZpdG5lc3MiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwgIiM0NTc1YjQiLCAiI2ZjOGQ1OSIpKQpgYGAKCiMtLS0tLS0tLS0tLS0tLSBwbG90IHRvZ2V0aGVyLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGFycmFuZ2UgdGhlIGhlYXQgbWFwCmdnYXJyYW5nZShtY19hLCBtY19wYXJ0aXRpb24sIG5jb2wgPSAyLCBucm93ID0gMSwgbGFiZWxzID0gYygiQSIsICJCIiksIGFsaWduID0gImgiKQoKIyBzYXZlCmdnc2F2ZSh1bml0cyA9ICJweCIsIGRwaSA9IDMwMCwgd2lkdGggPSAyMTAwLCBoZWlnaHQgPSAxNDAwLCBmaWxlbmFtZSA9IGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vTUMudGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS41KQpgYGAKCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgZHVhbCBjdWUgb3B0aW1pemF0aW9uIGZpZ3VyZQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuX2hpZ2guUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9wYXJfdG9faG1fdGUuUiIpKQpgYGAKCiMtLS0tLS0tLS0tIHBsb3R0aW5nIGZpdG5lc3Mgb2YgZHVhbCB2cyBzaW5nbGUgY3VlIG9wdCAtLS0tLS0tLS0jCiMgaW1wb3J0IGluIHByZXZpb3VzIGRhdGEKYGBge3J9CiMgZHVhbCBjdWUgZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9kdWFsX2N1ZV9vcHQ0L2R1YWxfY3VlX2ZpdG5lc3NfMjAuY3N2IikpCiMjIG1ha2UgbGFiZWwgYW5kIGZpbHRlciBvdXQgdmVyeSBsb3cgZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSAKICBtdXRhdGUodGVtcF9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsKSwKICAgICAgICAgdGVtcF9sYWJlbF9iID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYiksCiAgICAgICAgIGxhYmVsX2ZpbmFsID0gcGFzdGUwKHRlbXBfbGFiZWwsICIrIiwgdGVtcF9sYWJlbF9iKSkgJT4lIAogIGZpbHRlcih2YWx1ZSA+IDIpCgojIGdldCBzaW5nbGUgY3VlIGZpdG5lc3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKc2lfZml0bmVzcy5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bSIgJiB0aW1lID09IDIwKQoKIyBqb2luIHNpIGFuZCBkdWFsIGN1ZQpkdWFsX3NpX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGlkLCBzaV9maXRuZXNzID0gdmFsdWUpLCBieSA9ICJpZCIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGlkX2IgPSBpZCwgc2lfZml0bmVzc19iID0gdmFsdWUpLCBieSA9ICJpZF9iIikgJT4lIAogIG11dGF0ZShzaV9maXRuZXNzX21heCA9IGlmZWxzZShzaV9maXRuZXNzID4gc2lfZml0bmVzc19iLCBzaV9maXRuZXNzLCBzaV9maXRuZXNzX2IpLAogICAgICAgICBkdWFsX2xhYmVsID0gZ3N1YigibG9nIiwgImxvZzEwIiwgcGFzdGUobGFiZWwsICIrIiwgbGFiZWxfYikpKQpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9zaV9maXRuZXNzLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX3NpX2ZpdG5lc3MuZGYsIGFlcyh5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZHVhbF9sYWJlbCwgdmFsdWUpLCB4ID0gdmFsdWUsIGNvbG9yID0gIkR1YWwgY3VlIiwgc2hhcGUgPSAiRHVhbCBjdWUiKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9zaV9maXRuZXNzLmRmLCBhZXMoeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGR1YWxfbGFiZWwsIHZhbHVlKSwgeCA9IHNpX2ZpdG5lc3NfbWF4LCBjb2xvcj0gIkJlc3Qgc2luZ2xlIGN1ZSIsIHNoYXBlPSAiQmVzdCBzaW5nbGUgY3VlIiksIHNpemUgPSAzLCBhbHBoYSA9IDAuNykgKwogIGxhYnMoeCA9ICJGaXRuZXNzIiwgeSA9ICJEdWFsIGN1ZSIsIGNvbG9yID0gIkN1ZSIsIHNoYXBlID0gIkN1ZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNmYzhkNTkiLCAiIzQ1NzViNCIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOS44ODM2MDIpICsKICBnZW9tX3RleHQoYWVzKHg9OS44ODM2MDIsIGxhYmVsPSJcbklkZWFsIGZpdG5lc3MgKGRmPTkpIiwgeSA9ICJHICsgUiBsb2cxMCIpLCBhbmdsZT05MCkgKwogIHRoZW1lX2J3KCkKYGBgCgoKIy0tLS0tLS0tLS0tIHRpbWUgc2VyaWVzIGNvbnZlcnNpb24gcmF0ZSAtLS0tLS0tLS0tLS0tIwojIGR5bmFtaWNzIHNpbXVsYXRpb24gb2YgaGlnaCBwYXJhbWV0ZXIgY3VlcyAodGhlc2Ugc2VydmUgYXMgcmVmZXJlbmNlIHBvaW50cykKYGBge3J9CiMgYmVzdCBkdWFsIGN1ZSBjb21ibwpkdWFsLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuKAogIHBhcmFtZXRlcnNfY3IgPSBjKDQuNDQ2MTkyMDMzLAkxMC45NzUxODI3NSwJMS4zODc2MjgxNywJMjMuMzA1OTI1NCwJLTMuNDUyMDUyMzcxLAktMTguMDA3MDY5MiwJMzkuNjY2MTQyMjYsCS0zLjU0NTE5MzE0MSwJMTguNzgzNTA3OTkpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoNiwgNywgYnkgPSAxLzUwMCksCiAgY3VlX3JhbmdlX2IgPSBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMCksCiAgY3VlID0gIlIiLAogIGN1ZV9iID0gIkkiLAogIGxvZ19jdWUgPSAibG9nMTAiLAogIGxvZ19jdWVfYiA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQKKQoKIyB3aGVuIHRpbWUgaXMgdXNlZCBhcyBhIGN1ZSAoaGlnaCBwYXJhbWV0ZXIpCnRpbWUuY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW5faGlnaCgKICBwYXJhbWV0ZXJzX2NyID0gYyg5LjE1NDMxNCwgIC03LjU3MDgyOSwgLTIyLjUwNjYzOCAsICAzLjM4MjQwNSAsLTEzLjQ1MzUxOSAsLTE3LjAxMTQ4NSAgLCAzLjY3ODE4MSwgLTEyLjg1MTg5NSAsLTI2LjExNTE1OCksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWUgPSAidCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHdoZW4gYXNleHVhbCBpUkJDIGlzIHVzZWQgYXMgYSBjdWUgKGhpZ2ggZmxleGliaWxpdHkpCklfaGlnaC5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbl9oaWdoKAogIHBhcmFtZXRlcnNfY3IgPSBjKDEuMjk2Njc1LCAgMy41NDQwMzQgLCA0LjkwNzQ4NCwgIDIuMTc0MjQ5LCAtMy4yMzgzMDkgLC01LjE4MTYxNCAsLTEuNjQ1MDcyICwgMS44MzQzMDIgLCAxLjU4MTAxMSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCksCiAgY3VlID0gIkkiLAogIGxvZ19jdWUgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyB3aGVuIGFzZXh1YWwgaVJCQyBpcyB1c2VkIGFzIGEgY3VlIChub3JtYWwgZmxleGliaWxpdHkpCkkuY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW4oCiAgcGFyYW1ldGVyc19jciA9IGMoNS40NjM1NTgsCTIuMzgzOTQ4LAktMTcuNzU3MjgxLAk0LjU3MTgzNSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCksCiAgY3VlID0gIkkiLAogIGxvZ19jdWUgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyBwcm9jZXNzIApJX2hpZ2guY3IyIDwtIElfaGlnaC5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIkkgbG9nMTAgKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgpJLmNyMiA8LSBJLmNyICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikgJT4lIG11dGF0ZShsYWJlbF9uZXcgPSAiSSBsb2cxMCAoZGY9MykiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCnRpbWVfaGlnaC5jcjIgPC0gdGltZS5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIklkZWFsIChkZj05KSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKZHVhbC5jcjIgPC0gZHVhbC5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIlIgbG9nMTAgKyBJIGxvZzEwIChkZj05KSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKIyBjb21iaW5lCmR1YWxfY3IuZGYgPC0gcmJpbmQoSV9oaWdoLmNyMiwgSS5jcjIsIHRpbWVfaGlnaC5jcjIsIGR1YWwuY3IyKQpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsX2NyLmRmLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUpLCBzaXplID0gMSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfY3IuZGYgJT4lIGZpbHRlcih0aW1lJSUxID09IDApLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUsIHNoYXBlID0gbGFiZWxfbmV3KSwgc2l6ZSA9IDMpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIGNvbG9yID0gIkN1ZSIsIHNoYXBlID0gIkN1ZSIpICsKICB4bGltKDAsIDIwKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNmYzhkNTkiLCIjZmRjYjQ0IiwiYmxhY2siLCAiIzQ1NzViNCIpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpKQpgYGAKCiMtLS0tLS0tLS0tLS0gcmVhY3Rpb24gbm9ybSBoZWF0bWFwIG9mIFIgbG9nMTAgKyBJIGxvZzEwIC0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgbWFrZSBoZWF0bWFwIGRmClJfSS5obSA8LSBwYXJfdG9faG1fdGUocGFyID0gYyg0LjQ0NjE5MjAzMywJMTAuOTc1MTgyNzUsCTEuMzg3NjI4MTcsCTIzLjMwNTkyNTQsCS0zLjQ1MjA1MjM3MSwJLTE4LjAwNzA2OTIsCTM5LjY2NjE0MjI2LAktMy41NDUxOTMxNDEsCTE4Ljc4MzUwNzk5KSwKICAgICAgICAgICAgIGN1ZV9yYW5nZSA9IHNlcSg2LAk3LCBsZW5ndGgub3V0ID0gNTAwKSwKICAgICAgICAgICAgIGN1ZV9yYW5nZV9iID0gc2VxKDAsCTYuNzc4MTUxMjUsIGxlbmd0aC5vdXQgPSA1MDApKQoKIyBwcm9jZXNzIGR5bmFtaWNzClJfSS5keW4gPC0gZHVhbC5jciAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShsb2dfUiA9IGxvZzEwKFIpLAogICAgICAgICBsb2dfSSA9IGxvZzEwKEkpKQoKIyBleGFtaW5lIHNleHVhbCBpUkJDIGFzIHdlbGwKUl9JZy5keW4gPC0gZHVhbC5jciAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShsb2dfUiA9IGxvZzEwKFIpLAogICAgICAgICBsb2dfSWcgPSBsb2cxMChJZykpCm1heChSX0lnLmR5biRJZykgCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX3JuLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gUl9JLmhtLCBhZXMoeCA9IGN1ZV9yYW5nZV9iLCB5ID0gY3VlX3JhbmdlLCBmaWxsID0gY3IpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0kuZHluLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0kuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICB4bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSwgMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSkgKwogIHlsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpLDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCkpICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9kYXJrKCkKCiMganVzdCB0ZXN0aW5nIGZvciBzZXh1YWwgaVJCQyB2cyBSQkMKZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gUl9JZy5keW4sIGFlcyh4ID0gSWcsIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIiwgYXJyb3cgPSBhcnJvdyhhbmdsZSA9IDMwLCBsZW5ndGggPSB1bml0KDAuMSwgImluY2hlcyIpKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IFJfSWcuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IElnLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiKSArCiAgeGxpbSgwLCAyMDAwMDApICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJTZXh1YWwgaVJCQyBsb2cxMCIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2RhcmsoKQpgYGAKCiMgc2F2ZSBmaWd1cmUgZm9yIHBvc3RlcgpgYGB7cn0KZHVhbF9ybi5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBSX0kuaG0sIGFlcyh4ID0gY3VlX3JhbmdlX2IsIHkgPSBjdWVfcmFuZ2UsIGZpbGwgPSBjcikpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICBnZW9tX3BhdGgoZGF0YSA9IFJfSS5keW4sIGFlcyh4ID0gbG9nX0ksIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIiwgYXJyb3cgPSBhcnJvdyhhbmdsZSA9IDMwLCBsZW5ndGggPSB1bml0KDAuMSwgImluY2hlcyIpKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IFJfSS5keW4gJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAxICYgdGltZSA8PSAyMCksIGFlcyh4ID0gbG9nX0ksIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIikgKwogIHhsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX0kpLCBuYS5ybSA9IFQpLCAxLjAxKiBtYXgoaGFibGFyOjpzKFJfSS5keW4kbG9nX0kpLCBuYS5ybSA9IFQpKSArCiAgeWxpbSgwLjk5Km1pbihoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCksMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19SKSwgbmEucm0gPSBUKSkgKwogIGxhYnMoeSA9ICJSQkMgbG9nMTAiLCB4ID0gIkFzZXh1YWwgaVJCQyBsb2cxMCIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2RhcmsoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikgCgpkdWFsX2NyLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsX2NyLmRmLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUpLCBzaXplID0gMSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfY3IuZGYgJT4lIGZpbHRlcih0aW1lJSUxID09IDApLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUsIHNoYXBlID0gbGFiZWxfbmV3KSwgc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIGNvbG9yID0gIkN1ZSIsIHNoYXBlID0gIkN1ZSIpICsKICB4bGltKDAsIDIwKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM0NTc1YjQiLCAiIzkxYmZkYiIsIiNmYzhkNTkiLCIjZmRjYjQ0IikpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkpCgpnZ2FycmFuZ2UoZHVhbF9jci5wbDIsIGR1YWxfcm4ucGwyLCBhbGlnbiA9ICJoIiwgd2lkdGhzID0gYygxLjI1LCAxKSkKZ2dzYXZlKGhlcmUoInBvc3Rlci9kdWFsX2N1ZS5wbmciKSwgd2lkdGggPSA3LCBoZWlnaHQgPSA0KQpgYGAKCgojLS0tLS0tLS0gYXNzZW1ibGUgZmluYWwgZmlndXJlIC0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGFzc2VtYmxlIHBhbmVsIEIgYW5kIEMKZHVhbF9wbC5CQyA8LSBnZ2FycmFuZ2UoZHVhbF9jci5wbCwgZHVhbF9ybi5wbCwgYWxpZ24gPSAidiIsIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJCIiwgIkMiKSkKCiMgYXNzZW1ibGUgcGFuZWwgQQpnZ2FycmFuZ2UoZHVhbF9zaV9maXRuZXNzLnBsLCBkdWFsX3BsLkJDLCBuY29sID0gMiwgbGFiZWxzID0gYygiQSIsICIiKSwgd2lkdGhzID0gYygxLCAwLjc1KSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9jdWUudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTQwMCwgc2NhbGUgPSAxLjUsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBkeW5hbWljcyBvZiBkdWFsIGN1ZSBzaW11bGF0aW9uIChhbGwgY29tYmluYXRpb25zKQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgY29udmVyc2lvbiByYXRlCmBgYHtyfQojIGltcG9ydCBpbiBkdWFsIGN1ZSBkeW5hbWljcwpkdWFsX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kdWFsX2N1ZV9keW4vZHVhbF9jdWVfZHluLnBhcnF1ZXQiKSkKCiMga2VlcCBvbmx5IGNyIGFuZCBtYWtlIGxhYmVscyBmb3IgcGxvdHRpbmcuIHdlIGFyZSBnb2luZyB0byBvbWl0IGFueSBjdWUgY29tYmluYXRpb25zIGNvbnRhaW5pbmcgSStJZyBkdWUgdG8gdGhvc2Ugbm90IG9wdGltaXppbmcgYXQgYWxsCmR1YWxfY3IuZGZfcCA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJjciIgJiBjdWUgIT0gIkkrSWciICYgY3VlX2IgIT0gIkkrSWciKSAlPiUgCiAgbXV0YXRlKGxhYmVsX3Bsb3QgPSBwYXN0ZShsYWJlbCwgIisiLCBsYWJlbF9iKSkgJT4lIAogIGdyb3VwX2J5KGxhYmVsX3Bsb3QpICU+JSAKICBhcnJhbmdlKHRpbWUsIC5ieV9ncm91cCA9IFQpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09IDEpICU+JSAgIyBjdXQgZG93biBvbiBudW1iZXIgb2Ygcm93cwogIGxlZnRfam9pbihzZWxlY3QoZHVhbF9maXRuZXNzLmRmLCBpZCwgaWRfYiwgZml0bmVzcyA9IHZhbHVlKSwgYnkgPSBjKCJpZCIsICJpZF9iIikpICMgZ2V0IGZpdG5lc3MKCiMgcGxvdCByYXN0ZXIKZ2dwbG90KGRhdGEgPSBkdWFsX2NyLmRmX3AsIGFlcyh4ID0gdGltZSwgeSA9IGZjdF9yZW9yZGVyKGxhYmVsX3Bsb3QsIGZpdG5lc3MpLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV9yYXN0ZXIoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgeGxpbSgxLCAyMCkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiRHVhbCBjdWUgY29tYmluYXRpb24iLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9idygpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1ZV9jci50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNTAwLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCiMgY3VtdWx0YXRpdmUgdHJhbnNtaXNzaW9uIHRyYW5zbWlzc2lvbiBwb3RlbnRpYWwKUHJvdmluZyBhIHBvaW50IHRvIG15c2VsZgpgYGB7cn0KZHVhbF90YXUuZGZfcCA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtIiAmIGN1ZSAhPSAiSStJZyIgJiBjdWVfYiAhPSAiSStJZyIpICU+JSAKICBtdXRhdGUobGFiZWxfcGxvdCA9IHBhc3RlKGxhYmVsLCAiKyIsIGxhYmVsX2IpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfcGxvdCkgJT4lIAogIGFycmFuZ2UodGltZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0gMSkgJT4lICAjIGN1dCBkb3duIG9uIG51bWJlciBvZiByb3dzCiAgbGVmdF9qb2luKHNlbGVjdChkdWFsX2ZpdG5lc3MuZGYsIGlkLCBpZF9iLCBmaXRuZXNzID0gdmFsdWUpLCBieSA9IGMoImlkIiwgImlkX2IiKSkgJT4lICAjIGdldCBmaXRuZXNzIAogIGZpbHRlcihmaXRuZXNzID4gOS42NSkKCiMgaXQgc2VlbXMgdGhhdCBSIGxvZytJIGxvZyBvbmx5IGluY2hlcyBhaGVhZCBvZiBvdGhlciBhdCB0aGUgdmVyeSBlbmQgb2YgdGhlIGluZmVjdGlvbiwgc3VnZ2VzdGluZyB0aGF0IHRlcm1pbmFsIGludmVzdG1lbnQgaXMgYXQgcGxheQpnZ3Bsb3QoZGF0YSA9IGR1YWxfdGF1LmRmX3AsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLCBjb2xvciA9IGxhYmVsX3Bsb3QpKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIHhsaW0oMTUsIDIwKSArCiAgeWxpbSg1LDEwKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJEdWFsIGN1ZSBjb21iaW5hdGlvbiIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2J3KCkKYGBgCgoKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZ2V0IGR1YWwgY3VlIGRpc2Vhc2UgbWFwIChzaW11bGF0ZWQpCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKSSBhbSBnb2luZyB0byB0YWtlIHRoZSBvcHRpbWFsIGR5bmFtaWMgKFIgbG9nMTAgKyBJIGxvZzEwKSBhbmQgcGxvdCBhbGwgcG9zc2libGUgZGlzZWFzZSBjdXJ2ZXMgYW5kIHNlZSBpZiBhbnkgZm9sbG93IHRoZSBoeXN0ZXJlc2lzIGN1cnZlLiBTZWUgYmVsb3cgZm9yIHJlYWwgbGlmZSBkaXNlYXNlIGN1cnZlLgoKIyBwcm9jZXNzIApgYGB7cn0KIyBnZXQgbGlzdCBvZiBpbnRlcmVzdGVkIHZhcmlhYmxlcyBmb3IgcGxvdHRpbmcuIGRyb3AgY3IsIGZpdG5lc3MsIGFuZCBkZWF0aCBwcm9iYWJpbGl0eSwgaW1tdW5pdHksIGFuZCBtZXJvem9pdGVzICh3aGljaCBpcyBub3Qgb3B0aW1pemVkIGluIGR1YWwgY3VlKQpkdWFsX3Zhci5scyA8LSB1bmlxdWUoZHVhbC5jciR2YXJpYWJsZSlbIXVuaXF1ZShkdWFsLmNyJHZhcmlhYmxlKSAlaW4lIGMoInRhdSIsICJ0YXVfY3VtIiwgImNyIiwgImNyX3QiLCAiSUQiLCAiTiIsICJXIiwgIk0iLCAiTWciKV0KCiMgY3JlYXRlIGFsbCBwb3NzaWJsZSB2YXJpYWJsZSBjb21iaW5hdGlvbnMuIDYgdmFyaWFibGUgY29tYmluYXRpb24gKDQqNCB3aXRoIDQgc2FtZSByZWR1bmRhbnQgYW5kIGhhbGYgb2YgdGhhdCkgaXMgZXhwZWN0ZWQKZHVhbF92YXIuY29tYiA8LSB0aWR5cjo6ZXhwYW5kX2dyaWQoeCA9IGR1YWxfdmFyLmxzLAogICAgICAgICAgICAgICAgICAgICAgeSA9IGR1YWxfdmFyLmxzKSAlPiUgCiAgZmlsdGVyKHggIT0geSkgJT4lIAogIG11dGF0ZSh0bXAgPSBwYXN0ZTAocG1pbih4LCB5KSwgcG1heCh4LCB5KSkpICU+JSAjIGVsaW1pbmF0ZSBzYW1lIHZhcmlhYmxlIGJ1dCBkaWZmZXJlbnQgb3JkZXIKICBzbGljZV9oZWFkKG4gPSAxLCBieSA9IHRtcCkgJT4lIAogIHNlbGVjdCgtdG1wKQoKZHVhbF92YXIuY29tYgoKIyBmaWx0ZXIgb3V0IGludGVybWVkaWF0ZSBkYXRhIHBvaW50cyBpbiBkeW5hbWljIHNvIHdlIGNvdWxkIGhhdmUgZmFzdGVyIHBsb3R0aW5nLiBBbHNvIG1ha2Ugd2lkZXIgZm9yIHBsb3R0aW5nCiMjIGZpbHRlcmluZyBvdXQgYWxsIChub25lIGNyIHZhcmlhYmxlKSB2YWx1ZSBiZWxvdyAxIHNvIG5lZ2F0aXZlIHZsdWVzIGRvIG5vdCBvdmVyd2hlbG0gZGlzZWFzZSBjdXJ2ZS4gRm9yIGNyLCBrZWVwIG9ubHkgdmFsdWUgYmVsb3cgb3IgZXF1YWwgdG8gMQpkdWFsX2NyLmYgPC0gZHVhbC5jciAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlICVpbiUgYyhkdWFsX3Zhci5scywgImNyIikgJiBjYXNlX3doZW4odmFyaWFibGUgIT0gImNyIiB+IHZhbHVlID4gMSwgVH4gdmFsdWUgPD0xKSkgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIGlkX2NvbHMgPSBjKHRpbWUpKSAlPiUgCiAgYXJyYW5nZSh0aW1lKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAgPT0gMSkgCgpgYGAKCiMgcGxvdApgYGB7cn0KIyBtYWtlIHBhdGggcGxvdAojIyBubyBsb2dnZWQgb24geCBhbmQgeQpkdWFsX2N1cnZlLnBsIDwtIHB1cnJyOjptYXAyKC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAgICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gLnksIHkgPSAueCwgY29sb3IgPSAiY3IiKSwKICAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoYyhyZXAoMCwgbnJvdyhkdWFsX2NyLmYpIC0gMiksIDAuMjUpLCAiaW5jaGVzIikpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IC55LCB5ID0gLngsIGNvbG9yID0gImNyIiksIHNpemUgPSAzKSArCiAgICAgICAgICBsYWJzKGNvbG9yID0gIkNvbnZlcnNpb24gcmF0ZSIpICsgIyBub3RlIHRoZSBsYWJlbHMgYXJlIHJldmVyc2VkIGJlY2F1c2Ugd2Ugc2V0IHg9IHkgYW5kIHkgPSB4IGFib3ZlCiAgICAgICAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjaWVudGlmaWMpICsKICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2llbnRpZmljKSArCiAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChyZXAoMC4zLDQpLCAibGluZXMiKSwKICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAgICAgICB9CiAgICAgICAgICApCgojIyBsb2dnZWQgb24geApkdWFsX2N1cnZlX3hsb2cucGwgPC0gcHVycnI6Om1hcDIoCiAgLnggPSBkdWFsX3Zhci5jb21iJHgsIAogIC55ID0gZHVhbF92YXIuY29tYiR5LAogICAgICB+e2dncGxvdCgpICsKICAgICAgICAgIGdlb21fcGF0aChkYXRhID0gZHVhbF9jci5mLCBhZXNfc3RyaW5nKHggPSBzcHJpbnRmKCJsb2coJXMpIiwgLnkpLCB5ID0gLngsIGNvbG9yID0gImNyIiksCiAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KGMocmVwKDAsIG5yb3coZHVhbF9jci5mKSAtIDIpLCAwLjI1KSwgImluY2hlcyIpKSwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IHNwcmludGYoImxvZyglcykiLCAueSksIHkgPSAueCwgY29sb3IgPSAiY3IiKSwgc2l6ZSA9IDMpICsKICAgICAgICAgIGxhYnMoY29sb3IgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgeCA9IHBhc3RlMCgibG9nMTAoIiwgLnksIikiKSkgKyAjIG5vdGUgdGhlIGxhYmVscyBhcmUgcmV2ZXJzZWQgYmVjYXVzZSB3ZSBzZXQgeD0geSBhbmQgeSA9IHggYWJvdmUKICAgICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NpZW50aWZpYykgKwogICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQocmVwKDAuMyw0KSwgImxpbmVzIiksCiAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgICAgICAgfQogICAgICAgICAgKQoKIyMgbG9nZ2VkIG9uIHkKZHVhbF9jdXJ2ZV95bG9nLnBsIDwtIHB1cnJyOjptYXAyKAogIC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gLnksIHkgPSBzcHJpbnRmKCJsb2coJXMpIiwgLngpLCBjb2xvciA9ICJjciIpLAogICAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdChjKHJlcCgwLCBucm93KGR1YWxfY3IuZikgLSAyKSwgMC4yNSksICJpbmNoZXMiKSksCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5mICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09MSksIAogICAgICAgICAgICAgICAgICAgICBhZXNfc3RyaW5nKHggPSAueSwgeSA9IHNwcmludGYoImxvZyglcykiLCAueCksIGNvbG9yID0gImNyIiksIHNpemUgPSAzKSArCiAgICAgICAgICBsYWJzKGNvbG9yID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgIHkgPSBwYXN0ZTAoImxvZzEwKCIsIC54LCIpIikpICsgIyBub3RlIHRoZSBsYWJlbHMgYXJlIHJldmVyc2VkIGJlY2F1c2Ugd2Ugc2V0IHg9IHkgYW5kIHkgPSB4IGFib3ZlCiAgICAgICAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjaWVudGlmaWMpICsKICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLjMsNCksICJsaW5lcyIpLAogICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICAgICAgIH0KICAgICAgICAgICkKCgojIGJvdGggbG9nZ2VkCmR1YWxfY3VydmVfbG9nLnBsIDwtIHB1cnJyOjptYXAyKAogIC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gc3ByaW50ZigibG9nKCVzKSIsIC55KSwgeSA9IHNwcmludGYoImxvZyglcykiLCAueCksIGNvbG9yID0gImNyIiksCiAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KGMocmVwKDAsIG5yb3coZHVhbF9jci5mKSAtIDIpLCAwLjI1KSwgImluY2hlcyIpKSwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IHNwcmludGYoImxvZyglcykiLCAueSksIHkgPSBzcHJpbnRmKCJsb2coJXMpIiwgLngpLCBjb2xvciA9ICJjciIpLCBzaXplID0gMykgKwogICAgICAgICAgbGFicyhjb2xvciA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICB4ID0gcGFzdGUwKCJsb2cxMCgiLCAueSwiKSIpLAogICAgICAgICAgICB5ID0gcGFzdGUwKCJsb2cxMCgiLCAueCwiKSIpKSArICMgbm90ZSB0aGUgbGFiZWxzIGFyZSByZXZlcnNlZCBiZWNhdXNlIHdlIHNldCB4PSB5IGFuZCB5ID0geCBhYm92ZQogICAgICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMCwgMSkpICsKICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLjMsNCksICJsaW5lcyIpLAogICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICAgICAgIH0KICAgICAgICAgICkKCiMgc2F2ZSBhbGwgNCBwbGF0ZXMKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZS5wbCwgbmNvbCA9IDIsIG5yb3cgPSAzLCBhbGlnbiA9ICJodiIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2R1YWxfY3VydmUxLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDEwMDAsIHNjYWxlID0gMS41LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQoKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZV94bG9nLnBsLCBuY29sID0gMiwgbnJvdyA9IDMsIGFsaWduID0gImh2IikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9jdXJ2ZTIudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMTAwMCwgc2NhbGUgPSAxLjUsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCgpnZ2FycmFuZ2UocGxvdGxpc3QgPSBkdWFsX2N1cnZlX3lsb2cucGwsIG5jb2wgPSAyLCBucm93ID0gMywgYWxpZ24gPSAiaHYiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1cnZlMy50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPTEwMDAsIHNjYWxlID0gMS41LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQoKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZV9sb2cucGwsIG5jb2wgPSAyLCBucm93ID0gMywgYWxpZ24gPSAiaHYiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1cnZlNC50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSAxMDAwLCBzY2FsZSA9IDEuNSwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIHJlYWwgbGlmZSBkaXNlYXNlIGN1cnZlCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBleGVjdXRlIGNvZGUgZnJvbSByZXBvcnQgMTAgdG8gZ2V0IGZpbmFsIGRhdGFzZXQKVGhlIGZvbGxvd2luZyBncmFwaHMgd2lsbCBiZSBtYWRlOgotIFIgdnMgaVJCQwotIFIgbG9nMTAgdnMgaVJCQwotIFIgdnMgaVJCQyBsb2cxMAotIFIgbG9nMTAgdnMgaVJCQyBsb2cxMAoKLSBHIHZzIGlSQkMKLSBHIGxvZzEwIHZzIGlSQkMKLSBHIHZzIGlSQkMgbG9nMTAKLSBHIGxvZzEwIHZzIGlSQkMgbG9nMTAKCi0gUiB2cyBHCi0gUiBsb2cxMCB2cyBHCi0gUiB2cyBHIGxvZzEwCi0gUiBsb2cxMCB2cyBHIGxvZzEwCgpSIG9uIHktYXhpcwpgYGB7cn0Kcl9pLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gUkJDLCB4ID0gYXNleCkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpyX2lsb2cuZGMgPC1nZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGFzZXgpKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpybG9nX2lsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQykgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQpgYGAKCkcgb24geS1heGlzCmBgYHtyfQpnX2kuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBnYW0sIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGdhbSwgeCA9IGFzZXgsIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiaVJCQyBwZXIgwrVMIiwgeSA9ICJHYW1ldG9jeXRlIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCmdsb2dfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKZ19pbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gZ2FtLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gZ2FtLCB4ID0gbG9nMTAoYXNleCksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoaVJCQykgcGVyIMK1TCIsIHkgPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpnbG9nX2lsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChnYW0pLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoZ2FtKSwgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKYGBgCgpSIHZzIEcKYGBge3J9CnJfZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGdhbSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBnYW0sIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcmxvZ19nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGdhbSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gZ2FtLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gIkdhbWV0b2N5dGUgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDIHBlciDCtUwpIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpyX2dsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBSQkMsIHggPSBsb2cxMChnYW0pKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGdhbSksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfZ2xvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChnYW0pKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChnYW0pLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQykgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQpgYGAKCiMgcGxvdCB0b2dldGhlcgpgYGB7cn0KZ2dhcnJhbmdlKHJfaS5kYywgcmxvZ19pLmRjLCByX2lsb2cuZGMsIHJsb2dfaWxvZy5kYywKICAgICAgICAgIGdfaS5kYywgZ2xvZ19pLmRjLCBnX2lsb2cuZGMsIGdsb2dfaWxvZy5kYywKICAgICAgICAgIHJfZy5kYywgcmxvZ19nLmRjLCByX2dsb2cuZGMsIHJsb2dfZ2xvZy5kYywgCiAgICAgICAgICBuY29sID0gNCwgbnJvdyA9IDMsIGFsaWduID0gImh2IiwgY29tbW9uLmxlZ2VuZCA9IFQpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2V4cF9kaXNlYXNlLWN1cnZlLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE1MDAsIHNjYWxlID0gMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBzdGF0aWMgY29tcGV0aXRpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tIGhlYXQgbWFwIC0tLS0tLS0tLS0tLS0tLSMKIyBjYWxjdWxhdGUgZml0bmVzcyBkaWZmZXJlbmNlIGZvciAyMCBkYXlzCmBgYHtyfQojIGdldCBkeW5hbWljcwpzdGF0aWMubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV9zdGF0aWMvIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCnN0YXRpYy5scyA8LSBsYXBwbHkoc3RhdGljLmxzLCByZWFkX3BhcnF1ZXQpCgojIGdldCBmaXRuZXNzIGF0IGRheSAyMCAob3B0aW1pemVkIGZvciAyMCBkYXlzKQpzdGF0aWNfZml0bmVzcy5scyA8LSBtY2xhcHBseShzdGF0aWMubHMsIGZ1bmN0aW9uKHgpewogIHggJT4lIGZpbHRlcih0aW1lID09IDIwICYgdmFyaWFibGUgJWluJSBjKCJ0YXVfY3VtMSIsICJ0YXVfY3VtMiIpKQp9KQpzdGF0aWNfZml0bmVzcy5kZiA8LSBkby5jYWxsKHJiaW5kLCBzdGF0aWNfZml0bmVzcy5scykKCnN0YXRpY19maXRuZXNzLmRmIDwtIHRpZHlyOjpwaXZvdF93aWRlcihzdGF0aWNfZml0bmVzcy5kZiwgbmFtZXNfZnJvbSA9ICJ2YXJpYWJsZSIsIGlkX2NvbHMgPSBjKCJpZF8xIiwgImlkXzIiKSkgJT4lIAogIGdyb3VwX2J5KGlkXzEsIGlkXzIpICU+JSAKICBtdXRhdGUoZml0bmVzc19kaWZmZXJlbmNlID0gdGF1X2N1bTEtdGF1X2N1bTIpCndyaXRlLmNzdihzdGF0aWNfZml0bmVzcy5kZiwgaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCmBgYAoKIyBpbXBvcnQgYW5kIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBpbXBvcnQgaW4gZGF0YXNldApzdGF0aWMuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCgojIGpvaW4gd2l0aCBsYWJlbGxpbmcKc3RhdGljLmRmMiA8LSBzdGF0aWMuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8xID0gbGFiZWxfY2kpLCBieSA9IGMoImlkXzEiID0gImlkX2NpIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2lfMiA9IGxhYmVsX2NpKSwgYnkgPSBjKCJpZF8yIiA9ICJpZF9jaSIpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX2NpXzEsIGxhYmVsX2NpXzIsIGZpdG5lc3NfZGlmZmVyZW5jZSkgJT4lIAogIG11dGF0ZShsYWJlbF9jaV8xID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfY2lfMSksCiAgICAgICAgIGxhYmVsX2NpXzIgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9jaV8yKSkKCiMgZ2V0IHJldmVyc2Ugb3JkZXIsIHdoaWNoIGlzIHNpbXBseSBpbnZvdmxlcyBzd2l0Y2hpbmcgdGhlIGN1ZXMgYXJvdW5kIHRoZSBtdWx0aXBseWluZyB0aGUgZml0bmVzcyBieSBuZWdhdGl2ZSAxCnN0YXRpYy5kZjMgPC0gc3RhdGljLmRmMgpuYW1lcyhzdGF0aWMuZGYzKSA8LSBjKCJsYWJlbF9jaV8yIiwgImxhYmVsX2NpXzEiLCAiZml0bmVzc19kaWZmZXJlbmNlIikKc3RhdGljLmRmMyRmaXRuZXNzX2RpZmZlcmVuY2UgPC0gc3RhdGljLmRmMiRmaXRuZXNzX2RpZmZlcmVuY2UgKiAtMQoKIyBqb2luCnN0YXRpYy5kZjQgPC0gcmJpbmQoc3RhdGljLmRmMiwgc3RhdGljLmRmMykKCiMgZ2V0IG1lYW4Kc3RhdGljLm1lYW4gPC0gc3RhdGljLmRmNCAlPiUgCiAgZGlzdGluY3QobGFiZWxfY2lfMSwgbGFiZWxfY2lfMiwgLmtlZXBfYWxsID0gVCkgJT4lIAogIGdyb3VwX2J5KGxhYmVsX2NpXzEpICU+JSAKICBzdW1tYXJpemUobWVhbl9maXRuZXNzID0gbWVhbihmaXRuZXNzX2RpZmZlcmVuY2UsIG5hLnJtID0gVCkpCiAgCgojIGpvaW4gc3RhdGljLmRmNCB3aXRoIG1lYW4gZm9yIG9yZGVyIHNvcnRpbmcKc3RhdGljLmRmNSA8LSBzdGF0aWMuZGY0ICU+JSAKICBsZWZ0X2pvaW4oc3RhdGljLm1lYW4sIGJ5ID0gImxhYmVsX2NpXzEiKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2NpXzEgPSBmY3RfcmVvcmRlcihsYWJlbF9jaV8xLCBtZWFuX2ZpdG5lc3MpLAogICAgICAgICBsYWJlbF9jaV8yID0gZmN0X3JlbGV2ZWwobGFiZWxfY2lfMiwgbGV2ZWxzKHN0YXRpYy5kZjUkbGFiZWxfY2lfMSkpKQpgYGAKCiMgcGxvdApgYGB7cn0KIyBoZWF0bWFwCnN0YXRpYy5wbDEgPC0gZ2dwbG90KGRhdGEgPSBzdGF0aWMuZGY1LCBhZXMoeCA9IGxhYmVsX2NpXzIsIHkgPSBsYWJlbF9jaV8xLCBtZWFuX2ZpdG5lc3MsIGZpbGwgPSBmaXRuZXNzX2RpZmZlcmVuY2UpKSsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gIiNmYzhkNTkiLCBoaWdoID0gIiM0NTc1YjQiLCBtaWQgPSAid2hpdGUiLCAKICAgbWlkcG9pbnQgPSAwLCBzcGFjZSA9ICJMYWIiLCBsaW0gPSBjKC0wLjk1LCAwLjk1KSwgbmFtZT0iRml0bmVzc1xuZGlmZmVyZW5jZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImxlZnQiLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSwKICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QubWFyZ2luPW1hcmdpbihyID0gLTEsIGwgPSAtMSwgdW5pdCA9ICJwdCIpKSArIAogIGxhYnMoeCA9ICJTdHJhaW4gMiBjdWUiLCB5ID0gIlN0cmFpbiAxIGN1ZSIpICsKICBjb29yZF9maXhlZCgpCgojIG1lYW4gCnN0YXRpYy5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSAgc3RhdGljLm1lYW4sIGFlcyh5ID0gZmN0X3Jlb3JkZXIobGFiZWxfY2lfMSwgbWVhbl9maXRuZXNzKSwgeCA9IG1lYW5fZml0bmVzcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh5ID0gIiIsIHggPSAiTWVhbiBmaXRuZXNzXG5kaWZmZXJlbmNlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKGwgPSAwKSwKICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKQoKZ2dhcnJhbmdlKHN0YXRpYy5wbDEsIHN0YXRpYy5wbDIsIGFsaWduID0gImh2Iiwgd2lkdGhzID0gYygxLCAwLjIpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9zdGF0aWNfY29tcGV0aXRpb25fYS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDEuMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojLS0tLS0tIGVmZmVjdCBjdWUgcGVyY2VwdGlvbiAtLS0tLS0tIwojIyBsb2dnaW5nCmBgYHtyfQojIGdldCBub24tbG9nZ2VkIHBhaXJpbmdzCnN0YXRpY19ub2xvZyA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSB0cmltd3MoZ3N1YigiXFwgLioiLCAiIiwgbGFiZWxfY2lfMSkpLAogICAgICAgICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSkgJT4lIAogIGZpbHRlcihsb2dfMSA9PSAibm9uZSIpCgpzdGF0aWNfbG9nIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJsb2ciKQoKc3RhdGljX2xvZy5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBOb25lID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBzZWxlY3Qoc3RhdGljX2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBMb2cgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIGJ5ID0gYygiY3VlXzEiLCAibGFiZWxfY2lfMiIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShOb25lKSAmICFpcy5uYShMb2cpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKExvZyA+IE5vbmUsICJMb2dnZWQgYmV0dGVyIiwgIk5vdCBsb2dnZWQgYmV0dGVyIikpCmBgYAoKIyBjb21iaW5lZApgYGB7cn0Kc3RhdGljX25vY29tYiA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJub25lIikKCnN0YXRpY19jb21iIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gImNvbWIiKQogIApzdGF0aWNfY29tYi5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2NvbWIsIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgU2VsZiA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgc2VsZWN0KHN0YXRpY19jb21iLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIFRvdGFsID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBieSA9IGMoImN1ZV8xIiwgImxvZ18xIiwgImxhYmVsX2NpXzIiKSkgJT4lIAogIGZpbHRlcighaXMubmEoVG90YWwpICYgIWlzLm5hKFNlbGYpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFRvdGFsID4gU2VsZiwgIlRvdGFsIGJldHRlciIsICJTZWxmIGJldHRlciIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc3RhdGljX2xvZy5wbCA8LSBnZ3BhaXJlZChzdGF0aWNfbG9nLmRmLCBjb25kMSA9ICJOb25lIiwgY29uZDIgPSAiTG9nIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vdCBsb2dnZWQgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIkxvZ2dlZCBiZXR0ZXIiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wLjEpCgpzdGF0aWNfY29tYi5wbCA8LSBnZ3BhaXJlZChzdGF0aWNfY29tYi5kZiwgY29uZDEgPSAiVG90YWwiLCBjb25kMiA9ICJTZWxmIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRvdGFsIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJTZWxmIGJldHRlciIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTAuMikKCmdnYXJyYW5nZShzdGF0aWNfbG9nLnBsLCBzdGF0aWNfY29tYi5wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vc3RhdGljX2NvbXBldGl0aW9uX2IudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMjAwMCwgc2NhbGUgPSAxLjIsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGludmFzaW9uIGFuYWx5c2lzCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGltcG9ydCBpbiBkYXRhIChhbHJlYWR5IDIwIGRheXMgKQpgYGB7cn0KaW52YWRlLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCmBgYAoKCiMgcHJvY2VzcyBkYXRhIGZvciBpbnZhc2lvbiBtYXRyaXgKYGBge3J9CmludmFkZS5tYXQgPC0gaW52YWRlLmRmICU+JSAKICBncm91cF9ieShWMSA9IHBtaW4obXV0X2lkLCByZXNfaWQpLCBWMiA9IHBtYXgobXV0X2lkLCByZXNfaWQpKSAlPiUgIyBncm91cCBieSBjdWUgY29tcGV0aXRpb24sIGlycmVnYXJkbGVzcyBvZiBvcmRlcgogIG11dGF0ZShpZF9hbHQgPSBwYXN0ZTAoVjEsIFYyKSwKICAgICAgICAgaW52YWRlID0gY2FzZV93aGVuKAogICAgICAgICAgIGZpdG5lc3MgPiAwIH4gImludmFkZSIsCiAgICAgICAgICAgZml0bmVzcyA8IDAgfiAibm90IGludmFkZSIKICAgICAgICAgKSkgJT4lIAogIGdyb3VwX2J5KGlkX2FsdCkgJT4lIAogIG11dGF0ZSgKICAgIG11dF9pc19WMSA9IGNhc2Vfd2hlbigKICAgIG11dF9pZCA9PSBWMSB+ICJWMV9pbnZhZGUiLAogICAgbXV0X2lkICE9IFYxIH4gIlYxX2ludmFkZWQiKSkgJT4lIAogIGFycmFuZ2UoaWRfYWx0KSAlPiUgCiAgc2VsZWN0KGZpdG5lc3MsIFYxLCBWMiwgaWRfYWx0LCBpbnZhZGUsIG11dF9pc19WMSkgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbXV0X2lzX1YxLCB2YWx1ZXNfZnJvbSA9IGZpdG5lc3MpICU+JSAKICBncm91cF9ieShpZF9hbHQpICU+JSAKICBtdXRhdGUoVjFfaW52YWRlMiA9IGdzdWIoIk5BIiwgIiIsIHBhc3RlMChWMV9pbnZhZGUsIGNvbGxhcHNlID0gIiIpKSwKICAgICAgICAgVjFfaW52YWRlZDIgPSBnc3ViKCJOQSIsICIiLCBwYXN0ZTAoVjFfaW52YWRlZCwgY29sbGFwc2UgPSAiIikpKSAlPiUgCiAgZGlzdGluY3QoaWRfYWx0LCAua2VlcF9hbGwgPSBUKSAlPiUgCiAgbXV0YXRlKAogICAgY2F0ZWdvcnkgPSBjYXNlX3doZW4oCiAgICBWMV9pbnZhZGUyID4gMCAmIFYxX2ludmFkZWQyID4gMCB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgVjFfaW52YWRlMiA+IDAgJiBWMV9pbnZhZGVkMiA8IDAgfiAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIsCiAgICBWMV9pbnZhZGUyIDwgMCAmIFYxX2ludmFkZWQyID4gMCB+ICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiwKICAgIFYxX2ludmFkZTIgPCAwICYgVjFfaW52YWRlZDIgPCAwIH4gIk11dHVhbCBub24taW52YXNpb24iCiAgKSkgJT4lIAogIHNlbGVjdChWMSwgVjIsIGludmFzaW9uID0gY2F0ZWdvcnkpCgppbnZhZGUuZGYgJT4lIGZpbHRlcihtdXRfaWQgPT0gIkctaV9ub25lIikKaW52YWRlLmRmICU+JSBmaWx0ZXIocmVzX2lkID09ICJHLWlfbm9uZSIpCmBgYAoKCmBgYHtyfQojIGZvciBwbG90dGluZywgbmVlZCB0byBnZXQgYWxsIHNhbWUgY3VlIHZzIHNhbWUgY3VlLCB3aGljaCB3ZSB3aWxsIHNldCB0byBOQQppbnZhZGUuTkEgPC0gY2JpbmQuZGF0YS5mcmFtZShgVjFgID0gdW5pcXVlKGludmFkZS5tYXQkVjEpLAogICAgICBgVjJgID0gdW5pcXVlKGludmFkZS5tYXQkVjEpLAogICAgICBpbnZhc2lvbiA9IE5BKQoKaW52YWRlLm1hdDIgPC0gcmJpbmQoaW52YWRlLm1hdCwgaW52YWRlLk5BKQoKIyBnZXQgbGFiZWwKaW52YWRlLm1hdDMgPC0gaW52YWRlLm1hdDIgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBWMV9sYWJlbCA9IGxhYmVsX2NpKSwgYnkgPSBjKCJWMSIgPSAiaWRfY2kiKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBWMl9sYWJlbCA9IGxhYmVsX2NpKSwgYnkgPSBjKCJWMiIgPSAiaWRfY2kiKSkgJT4lIAogIG11dGF0ZShWMV9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIFYxX2xhYmVsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWMl9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIFYyX2xhYmVsKSkKCgppbnZhZGUubWF0NCA8LSByYmluZCgKICBzZWxlY3QoaW52YWRlLm1hdDMsIFYxX2xhYmVsLCBWMl9sYWJlbCwgaW52YXNpb24pLAogIHNlbGVjdChpbnZhZGUubWF0MywgVjJfbGFiZWwgPSBWMV9sYWJlbCwgVjFfbGFiZWwgPSBWMl9sYWJlbCkgJT4lIG11dGF0ZShpbnZhc2lvbiA9IE5BKSkgJT4lCiAgbXV0YXRlKAogICAgaW52YXNpb25fMiA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJNdXR1YWwgaW52YXNpb24iIH4gIk11dHVhbCBpbnZhc2lvbiIsCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIgfiAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIsCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIgfiAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIKICApKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShWMV9sYWJlbCkpCgppbnZhZGUubWF0NCRWMV9sYWJlbCA8LSBmYWN0b3IoaW52YWRlLm1hdDQkVjFfbGFiZWwsIGxldmVscyA9ICBjKCJHIGxvZzEwIiwgIkciLCAiRzErRzIiLCAiSSBsb2cxMCIsICJJIiwgIkkrSWcgbG9nMTAiLCAiSStJZyIsICJJMStJMiBsb2cxMCIsICJJMStJMiIsICJJZyBsb2cxMCIsICJJZyIsICJJZzErSWcyIiwgIlIgbG9nMTAiLCAiUiIsICJzdW0gbG9nMTAiLCAic3VtIikpCmludmFkZS5tYXQ0JFYyX2xhYmVsIDwtIGZhY3RvcihpbnZhZGUubWF0NCRWMl9sYWJlbCwgbGV2ZWxzID0gIGMoIkciLCAiRzErRzIiLCAiSSBsb2cxMCIsICJJIiwgIkkrSWcgbG9nMTAiLCAiSStJZyIsICJJMStJMiBsb2cxMCIsICJJMStJMiIsICJJZyBsb2cxMCIsICJJZyIsICJJZzErSWcyIiwgIlIgbG9nMTAiLCAiUiIsICJzdW0gbG9nMTAiLCAic3VtIiwgIkcgbG9nMTAiKSkKYGBgCgoKIyBwbG90IGludmFzaW9uIG1hdHJpeApgYGB7cn0KaW52YXNpb24ucGwxIDwtIGdncGxvdChkYXRhID0gaW52YWRlLm1hdDQsIGFlcyh4ID0gVjJfbGFiZWwsIHkgPSBWMV9sYWJlbCwgZmlsbCA9IGludmFzaW9uXzIpKSArCiAgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIikgKwogIHRoZW1lX21pbmltYWwoKSArICAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSwKICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QubWFyZ2luPW1hcmdpbihyID0gMCkpICsgCiAgbGFicyhmaWxsID0gIkludmFzaWJpbGl0eSIsIHggPSAiQ29tcGV0aW5nIGN1ZSIsIHkgPSAiUmVmZXJlbmNlIGN1ZSIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIgPSAiIzQ1NzViNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIgPSAiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXV0dWFsIGludmFzaW9uIiA9ICIjZmVlMDkwIiksCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAid2hpdGUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMgY3JlYXRlIHN1bW1hcnkgYmFyIGNoYXJ0CmBgYHtyfQojIGNyZWF0ZSBhIHN0YWNrZWQgYmFyY2hhcnQgZm9yIHN1bW1hcnkKIyMgZmlsdGVyIG91dCBuYQppbnZhZGUubWF0YWx0IDwtIGludmFkZS5tYXQzICU+JSBuYS5leGNsdWRlKCkKCiMgZ2V0IGZycXVlbmN5IGZyb20gYm90aCBzaWRlcy4gTm90ZSB3aGVuIGdyb3VwaW5nIGZvciBWMiwgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgY3VlIDIsIHNjZW5hcnJpbyB3aGVuIHN0cmFpbiAyIGludmFkZSA9IHN0cmFpbiAxIGludmFkZQppbnZhZGUubWF0YWx0MSA8LSBpbnZhZGUubWF0YWx0ICU+JSBncm91cF9ieShWMV9sYWJlbCwgaW52YXNpb24pICU+JSAKICBzdW1tYXJpemUoZnJlcXVlbmN5XzEgPSBuKCkpCgppbnZhZGUubWF0YWx0MiA8LSBpbnZhZGUubWF0YWx0ICU+JQogIG11dGF0ZShpbnZhc2lvbl9hbHQgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIgfiAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIsCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIgfiAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIsCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIGludmFzaW9uIiB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk11dHVhbCBub24taW52YXNpb24iIH4gIk11dHVhbCBub24taW52YXNpb24iCiAgKSkgJT4lIAogIGdyb3VwX2J5KFYyX2xhYmVsLCBpbnZhc2lvbl9hbHQpICU+JSAKICBzdW1tYXJpemUoZnJlcXVlbmN5XzIgPSBuKCkpICAgICAKCiMgZnVsbCBqb2luIGFuZCBzdW0uIGhhcyBjb25maXJtZWQgYWxsIG9mIHRoZW0gYWRkIHVwIHRvIDE0IAppbnZhZGUubWF0YWx0MyA8LSBmdWxsX2pvaW4oaW52YWRlLm1hdGFsdDEsIGludmFkZS5tYXRhbHQyLCBieSA9IGMoIlYxX2xhYmVsIiA9ICJWMl9sYWJlbCIsICJpbnZhc2lvbiIgPSAiaW52YXNpb25fYWx0IikpCgppbnZhZGUubWF0YWx0M1tpcy5uYShpbnZhZGUubWF0YWx0MyldIDwtIDAKaW52YWRlLm1hdGFsdDQgPC0gaW52YWRlLm1hdGFsdDMgJT4lIAogIG11dGF0ZShmcmVxID0gZnJlcXVlbmN5XzEgKyBmcmVxdWVuY3lfMikgJT4lIAogIG11dGF0ZSh0ZW1wID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gZnJlcQogICkpICU+JSAKICBncm91cF9ieShWMV9sYWJlbCkgJT4lIAogIG11dGF0ZShpbnZhZGVfMV9mcmVxID0gbWF4KHRlbXAsIG5hLnJtID0gVCkpICU+JSAKICBtdXRhdGUoaW52YXNpb25fMiA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJNdXR1YWwgaW52YXNpb24iIH4gIk11dHVhbCBpbnZhc2lvbiIsCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIgfiAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIsCiAgICBpbnZhc2lvbiA9PSAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIgfiAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIKICApKQpgYGAKCgoKYGBge3J9CmludmFzaW9uLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoZGF0YSA9IGludmFkZS5tYXRhbHQ0LCBhZXMoeCA9IGZyZXEsIHkgPSByZW9yZGVyKFYxX2xhYmVsLCBpbnZhZGVfMV9mcmVxKSwgZmlsbCA9IGZvcmNhdHM6OmZjdF9yZXYoZmFjdG9yKGludmFzaW9uXzIsIGxldmVscyA9IGMoIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiLCAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIsICJNdXR1YWwgaW52YXNpb24iLCAiTXV0dWFsIG5vbi1pbnZhc2lvbiIpKSkpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnMoeCA9ICJGcmVxdWVuY3kiLCBmaWxsID0gIkludmFzaWJpbGl0eSIsIHkgPSAiQ3VlIikgKwogIHRoZW1lX2J3KCkgICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiA9ICIjNDU3NWI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb21wZXRpdGl2ZSBleGNsdXNpb25cbmJ5IGFub3RoZXIgY3VlIiA9ICIjZmM4ZDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdXR1YWwgaW52YXNpb24iID0gIiNmZWUwOTAiKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkKYGBgCgojIHBsb3QgdG9nZXRoZXIKYGBge3J9CmdnYXJyYW5nZShpbnZhc2lvbi5wbDEsIGludmFzaW9uLnBsMiwgYWxpZ24gPSAiaCIsIGNvbW1vbi5sZWdlbmQgPSBULCB3aWR0aHMgPSBjKDIsIDEpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9pbnZhc2lvbl9hLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDExMDAsIHNjYWxlID0gMS40LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCiMtLS0tLS0tLS0tLS0tLS0tIGludmFzaW9uIHBhaXJ3aXNlIGNvbXBhcmlzb24tLS0tLS0tLS0tLS0tLS0tLSMKIyMgcHJvY2VzIGRhdGEKYGBge3J9CiMgam9pbiBpbnZhZGUgZGYgd2l0aCBsYWJlbCBiZWNhdXNlIEkgYW0gbGF6eQppbnZhZGUuZGYyIDwtIGludmFkZS5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpXzEgPSBsYWJlbF9jaSksIGJ5ID0gYygibXV0X2lkIiA9ICJpZF9jaSIpKQoKaW52YWRlLmRmMiAKYGBgCgojIGxvZwpgYGB7cn0KIyBnZXQgbm9uLWxvZ2dlZCBwYWlyaW5ncwppbnZhZGVfbm9sb2cgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gIm5vbmUiKQoKCmludmFkZV9sb2cgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gImxvZyIpCgppbnZhZGVfbG9nLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3QoaW52YWRlX25vbG9nLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgTm9uZSA9IGZpdG5lc3MpLAogIHNlbGVjdChpbnZhZGVfbG9nLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgTG9nID0gZml0bmVzcyksCiAgYnkgPSBjKCJjdWVfMSIsICJyZXNfaWQiKSkgJT4lIAogIGZpbHRlcighaXMubmEoTm9uZSkgJiAhaXMubmEoTG9nKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShMb2cgPiBOb25lLCAiTG9nZ2VkIGJldHRlciIsICJOb3QgbG9nZ2VkIGJldHRlciIpKQoKaW52YWRlX2xvZwpgYGAKCiMgY29tYmluZWQKYGBge3J9CmludmFkZV9ub2NvbWIgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAibm9uZSIpCgppbnZhZGVfY29tYiA8LSBpbnZhZGUuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJjb21iIikKICAKaW52YWRlX2NvbWIuZGYgPC0gbGVmdF9qb2luKAogIHNlbGVjdChpbnZhZGVfbm9jb21iLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgU2VsZiA9IGZpdG5lc3MpLAogIHNlbGVjdChpbnZhZGVfY29tYiwgY3VlXzEsIHJlc19pZCwgbG9nXzEsIFRvdGFsID0gZml0bmVzcyksCiAgYnkgPSBjKCJjdWVfMSIsICJsb2dfMSIsICJyZXNfaWQiKSkgJT4lIAogIGZpbHRlcighaXMubmEoVG90YWwpICYgIWlzLm5hKFNlbGYpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFRvdGFsID4gU2VsZiwgIlRvdGFsIGJldHRlciIsICJTZWxmIGJldHRlciIpKQppbnZhZGVfY29tYi5kZgpgYGAKCiMgcGxvdApgYGB7cn0KaW52YWRlX2xvZy5wbCA8LSBnZ3BhaXJlZChpbnZhZGVfbG9nLmRmLCBjb25kMSA9ICJOb25lIiwgY29uZDIgPSAiTG9nIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vdCBsb2dnZWQgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIkxvZ2dlZCBiZXR0ZXIiID0gIiM0NTc1YjQiKSkrCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTApCgppbnZhZGVfY29tYi5wbCA8LSBnZ3BhaXJlZChpbnZhZGVfY29tYi5kZiwgY29uZDEgPSAiVG90YWwiLCBjb25kMiA9ICJTZWxmIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRvdGFsIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJTZWxmIGJldHRlciIgPSAiIzQ1NzViNCIpKSsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAtMCkKCmdnYXJyYW5nZShpbnZhZGVfbG9nLnBsLCBpbnZhZGVfY29tYi5wbCwgYWxpZ24gPSAiaCIsIG5jb2wgPSAyKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9pbnZhc2lvbl9iLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDkwMCwgc2NhbGUgPSAxLjIsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIEN1ZSBwZXJmb3JtYW5jZSBhY3Jvc3Mgc2luZ2xlLCBjby1pbmZlY3Rpb24sIHN0YXRpYywgYW5kIGludmFzaW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwpgYGB7cn0KIyBpbXBvcnQgaW4gYWxsIHRoZSByYW5rcwpzaV9vcHQuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9zaV9vcHQuY3N2IikpCmNpX29wdC5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX29wdC5jc3YiKSkKc3RhdGljLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQppbnZhc2lvbi5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQoKIyBjYWxjdWxhdGUgbWVhbiBmaXRuZXNzCnN0YXRpYy5tZWFuICMjIGFscmVhZHkgY2FsY3VsYXRlZAppbnZhc2lvbi5tZWFuIDwtIHJiaW5kKHNlbGVjdChpbnZhc2lvbi5kZiwgY3VlID0gbXV0X2lkLCBmaXRuZXNzKSwKICAgICAgc2VsZWN0KGludmFzaW9uLmRmICU+JSBtdXRhdGUoZml0bmVzczIgPSBmaXRuZXNzICogLTEpLCBjdWUgPSByZXNfaWQsIGZpdG5lc3MgPSBmaXRuZXNzMikpICU+JSAKICBncm91cF9ieShjdWUpICU+JSAKICBzdW1tYXJpemUobWVhbl9maXRuZXNzID0gbWVhbihmaXRuZXNzKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhtZWFuX2ZpdG5lc3MpKQoKIyBjYWxjdWxhdGUgcmFua3MKc2kucmFuayA8LSBzaV9vcHQuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBpZF9zaSwgbGFiZWwgPSBlel9sYWJlbF9zaSksIGJ5ID0gYygiaWQiID0gImlkX3NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IGRlbnNlX3JhbmsoLWZpdG5lc3NfMjApLAogICAgICAgICBtb2RlbCA9ICJTaW5nbGUgaW5mZWN0aW9uIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQgPSBpZF9jaSwgbGFiZWwpCgpjaS5yYW5rIDwtIGNpX29wdC5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChjaV9maXRuZXNzLmRmLCB2YWx1ZSwgbGFiZWwpLCBieSA9ICJsYWJlbCIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgaWRfc2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJpZCIgPSAiaWRfY2kiKSkgJT4lIAogIG11dGF0ZShyYW5rID0gcmFuaygtdmFsdWUpLAogICAgICAgICBtb2RlbCA9ICJDby1pbmZlY3Rpb24iKSAlPiUgCiAgc2VsZWN0KHJhbmssIG1vZGVsLCBpZCwgbGFiZWwgPSBlel9sYWJlbCkKCnN0YXRpYy5yYW5rIDwtIHN0YXRpYy5tZWFuICU+JSAKICBtdXRhdGUobGFiZWxfY2kgPSBnc3ViKCJsb2cxMCIsICJsb2ciLCBsYWJlbF9jaV8xKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaSwgZXpfbGFiZWwpLCBieSA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbF9jaSIpKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSByYW5rKC1tZWFuX2ZpdG5lc3MpLAogICAgICAgICBtb2RlbCA9ICJTdGF0aWMgbWl4ZWQgZ2Vub3R5cGUiKSAlPiUgCiAgc2VsZWN0KHJhbmssIG1vZGVsLCBpZCA9IGlkX2NpLCBsYWJlbCA9IGV6X2xhYmVsKQoKaW52YXNpb24ucmFuayA8LSBpbnZhc2lvbi5tZWFuICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgZXpfbGFiZWwpLCBieSA9IGMoImN1ZSIgPSAiaWRfY2kiKSkgJT4lIAogIG11dGF0ZShyYW5rID0gcmFuaygtbWVhbl9maXRuZXNzKSwKICAgICAgICAgbW9kZWwgPSAiSW52YXNpdmUgbWl4ZWQgZ2Vub3R5cGUiKSAlPiUgCiAgc2VsZWN0KHJhbmssIG1vZGVsLCBpZCA9IGN1ZSwgbGFiZWwgPSBlel9sYWJlbCkgJT4lIAogIG11dGF0ZShsYWJlbCA9IGdzdWIoIlxuIiwgIiAiLCBwYXN0ZTAoIiAgICIsIGxhYmVsKSkpCgpzdGF0aWMucmFuawojIGNvbmNhdGVuYXRlCmZpdG5lc3MucmFuayA8LSByYmluZCgKICBzaS5yYW5rLCBjaS5yYW5rLCBzdGF0aWMucmFuaywgaW52YXNpb24ucmFuawopICU+JSAKICBtdXRhdGUobW9kZWwgPSBmY3RfcmVsZXZlbChtb2RlbCwgYygiU2luZ2xlIGluZmVjdGlvbiIsICJDby1pbmZlY3Rpb24iLCAiU3RhdGljIG1peGVkIGdlbm90eXBlIiwgIkludmFzaXZlIG1peGVkIGdlbm90eXBlIikpKQoKIyBoaWdobGlnaHQgdGhlIGdvb2Qgb25lcwpmaXRuZXNzLnJhbmtfZ29vZCA8LSBmaXRuZXNzLnJhbmsgJT4lIAogIGZpbHRlcihpZCAlaW4lIGMoIklnLWlfbG9nIiwgIkktaStJZy1pX2xvZyIsICJzdW1fbG9nIiwgIkctaV9sb2ciKSkKYGBgCgojIHBsb3QKYGBge3J9CmxpYnJhcnkoZ2didW1wKQoKZ2dwbG90KCkgKwogIGdlb21fYnVtcChkYXRhID0gZml0bmVzcy5yYW5rLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgZ3JvdXAgPSBpZCksIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZml0bmVzcy5yYW5rLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgZ3JvdXAgPSBpZCksIGNvbG9yID0gImdyZXkiLCBzaXplID0gMykgKwogIGdlb21fYnVtcChkYXRhID0gZml0bmVzcy5yYW5rX2dvb2QsIGFlcyh4ID0gbW9kZWwsIHkgPSByYW5rLCBncm91cCA9IGlkLCBjb2xvciA9IGlkKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdG5lc3MucmFua19nb29kLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgZ3JvdXAgPSBpZCwgY29sb3IgPSBpZCksIHNpemUgPSAzKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBpbnZhc2lvbi5yYW5rLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgbGFiZWwgPSBsYWJlbCksIHNpemUgPSAzLjUsIGhqdXN0ID0gMCwgaW5oZXJpdC5hZXMgPSBGKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBleHBhbmRfbGltaXRzKHggPSA1LjUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHggPSAiTW9kZWwiLCB5ID0gIk1lYW4gZml0bmVzcyByYW5rIikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZml0bmVzc19yYW5rLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE1MDAsIHNjYWxlID0gMSwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgoKIy09PT09PT09PT09PT09PT09PT09PT0jCiMgUGFydGl0aW9uaW5nIGJlc3QgY3VlCiM9PT09PT09PT09PT09PT09PT09PT0tIwojLS0tLS0tLSBzaW5nbGUgaW5mZWN0aW9uIC0tLS0tLS0tLS0tIwojIHJlZG8gc29tZSBvcHRpbWl6YXRpb24gKGxvd2VyIGZpdG5lc3MgaW4gbm8gUiB0aGFuIGRlZmF1bHQpCmBgYHtyfQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuX1IuUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuX04uUiIpKQojIEkgbm9uZQpjbCA8LSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpKTsgc2V0RGVmYXVsdENsdXN0ZXIoY2wgPSBjbCkKSV9ub19SIDwtIG9wdGltUGFyYWxsZWwoCiAgICBwYXIgPSByZXAoMC41LDQpLCAjIHN0YXJ0IGF0IDAuNXg0CiAgICBmbiA9IGNoYWJhdWRpX3NpX2NsZWFuX1IsIAogICAgY29udHJvbCA9IGxpc3QodHJhY2UgPSA2LCBmbnNjYWxlID0gLTEpLAogICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogICAgY3VlX3JhbmdlID0gIHNlcSgwLCA2KigxMF42KSwgYnkgPSAoNiooMTBeNikpLzUwMDApLAogICAgY3VlID0gIkkiLAogICAgbG9nX2N1ZSA9ICJub25lIiwKICAgIHNvbHZlciA9ICJ2b2RlIikKc3RvcENsdXN0ZXIoY2wpCiMgMC4xNDQwMjEgLTQzLjEwNDYgMjAzMC4yNyAtNTI0LjY4NiAKIyA4LjY5NTg5CmBgYAoKIyBpbXBvcnQgYW5kIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBpbXBvcnQgaW4gZGF0YQpzaV9wYXJ0aXRpb24ubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2kvIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKc2lfcGFydGl0aW9uLmxzIDwtIGxhcHBseShzaV9wYXJ0aXRpb24ubHMsIHJlYWQuY3N2KQpzaV9wYXJ0aXRpb24uZGYgPC0gZG8uY2FsbChyYmluZCwgc2lfcGFydGl0aW9uLmxzKQoKIyBjb21iaW5lIHdpdGggc2kgZml0bmVzcyAoZGVmYXVsdCkKc2lfcGFydGl0aW9uLmRmIDwtIHNpX3BhcnRpdGlvbi5kZiAlPiUgbGVmdF9qb2luKHNlbGVjdChzaV9maXRuZXNzLmRmLCBpZCwgZml0bmVzcyA9IHZhbHVlKSwgYnkgPSAiaWQiKQoKIyBtYWtlIGxvbmdlcgpzaV9wYXJ0aXRpb24uZGYyIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIoc2lfcGFydGl0aW9uLmRmLCBjKGZpdG5lc3NfUiwgZml0bmVzc19OLCBmaXRuZXNzX1csIGZpdG5lc3MpKQoKIyBjYWxjdWxhdGUgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uLiBBbHNvIHJlbmFtZQpzaV9wYXJ0aXRpb24uZGYyIDwtIHNpX3BhcnRpdGlvbi5kZjIgJT4lIAogIGdyb3VwX2J5KG5hbWUpICU+JSAKICBtdXRhdGUoY3YgPSBzZCh2YWx1ZSkvbWVhbih2YWx1ZSkqMTAwLAogICAgICAgICBtZWFuID0gbWVhbih2YWx1ZSksCiAgICAgICAgIGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgICAgICAgIG5hbWUgPT0gImZpdG5lc3NfUiIgfiAiTm8gUkJDIGxpbWl0YXRpb24iLAogICAgICAgICAgIG5hbWUgPT0gImZpdG5lc3NfVyIgfiAiTm8gdGFyZ2V0ZWQgaW1tdW5pdHkiLAogICAgICAgICAgIG5hbWUgPT0gImZpdG5lc3NfTiIgfiAiTm8gaW5kaXNjcmltaW5hdGVcbmltbXVuaXR5IiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzIiB+ICJEZWZhdWx0IgogICAgICAgICApKQoKYGBgCgojIHBsb3QKYGBge3J9CmxpYnJhcnkodW5nZXZpeikKIyByYXcgZml0bmVzcwpzaV9wYXJ0aXRpb24ucGwxIDwtIGdncGxvdCgpICsKICBnZW9tX3ZwbGluZShkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSBtZWFuLCBncm91cCA9IGNhdGVnb3J5LCBjb2xvciA9IGNhdGVnb3J5KSwgc2hvdy5sZWdlbmQgPSBGLCBzaXplID0gMSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gdmFsdWUpLCBzaXplID0gMiwgYWxwaGEgPSAwLjcpICsKICBnZW9tX2xpbmUoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gdmFsdWUsIGdyb3VwID0gaWQpLCBhbHBoYSA9IDAuMikgKwogIGxhYnMoeCA9ICJGaXRuZXNzIiwgeSA9ICJDb25kaXRpb25zIikgKwogIHRoZW1lX2J3KCkKCiMgY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uCnNpX3BhcnRpdGlvbi5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IGN2KSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHggPSAiQ29lZmZpY2llbnQgb2ZcbnZhcmlhdGlvbiAoJSkiLCB5ID0gIiIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKQoKc2lfcGFydGl0aW9uLnBsIDwtIGdnYXJyYW5nZShzaV9wYXJ0aXRpb24ucGwxLCBzaV9wYXJ0aXRpb24ucGwyLCB3aWR0aHMgPSBjKDEsIDAuMyksIGFsaWduID0gImgiKQpzaV9wYXJ0aXRpb24ucGwKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3BhcnRpdGlvbl9maXRuZXNzLnRpZmYiKSwgd2lkdGggPSA3LCBoZWlnaHQgPSA0KQpgYGAKCiMtLS0tLS0tIGNvbnNlcXVlbmNlcyBvZiBubyB0YXJnZXRlZCBpbW11bml0eSAtLS0tLS0tLS0tLS0jCiMgZ2V0IGR5bmFtaWNzIG9mIG5vIHRhcmdldGVkIGltbXVuaXR5CmBgYHtyfQpnZXRfZHluIDwtIGZ1bmN0aW9uKGRmKXsKICAKICBzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuX1cuUiIpKQogIGlkIDwtIGRmJGlkCiAgY3VlIDwtIGRmJGN1ZQogIGxvZyA8LSBkZiRsb2cKICBwYXIgPC0gYyhkZiR2YXJfVzEsIGRmJHZhcl9XMiwgZGYkdmFyX1czLCBkZiR2YXJfVzQpCiAgY3VlX3JhbmdlIDwtIHNlcShkZiRsb3csIGRmJGhpZ2gsIGJ5ID0gZGYkYnkpCiAgCiAgIyBnZXQgZHluYW1pY3MKICBkeW4gPC0gY2hhYmF1ZGlfc2lfY2xlYW5fVygKICAgIHBhcmFtZXRlcnNfY3IgPSBwYXIsCiAgICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICAgIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgICBjdWVfcmFuZ2UgPSAgY3VlX3JhbmdlLAogICAgY3VlID0gY3VlLAogICAgbG9nX2N1ZSA9IGxvZywKICAgIHNvbHZlciA9ICJ2b2RlIiwKICAgIGR5biA9IFQKICApCiAgCiAgIyBjb21iaW5lCiAgZHluMiA8LSBjYmluZChkeW4sIGlkID0gaWQsIGN1ZSA9IGN1ZSwgbG9nID0gbG9nKQogIAogIHdyaXRlX3BhcnF1ZXQoZHluMiwgcGFzdGUwKGhlcmUoImRhdGEvcGFydGl0aW9uL3NpX2R5bi8iKSwgaWQsICJfbm9XX2R5bi5wYXJxdWV0IikpCiAgCn0KYGBgCgojIGdldCBkZiB0byBydW4KYGBge3J9CiMgam9pbiB3aXRoIGN1ZV9yYW5nZQpjdWVfcmFuZ2Vfc2kuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jdWVfcmFuZ2Vfc2kuY3N2IikpCnNpX3BhcnRpdGlvbi5kZjMgPC0gc2lfcGFydGl0aW9uLmRmICU+JSBsZWZ0X2pvaW4oc2VsZWN0KGN1ZV9yYW5nZV9zaS5kZiwgbG93LCBoaWdoLCBieSwgaWQpLCAiaWQiKQoKIyBsYXBwbHkgbG9vcApzaV9wYXJ0aXRpb24ubHMgPC0gc3BsaXQoc2lfcGFydGl0aW9uLmRmMywgc2VxKG5yb3coc2lfcGFydGl0aW9uLmRmMykpKQptY2xhcHBseShzaV9wYXJ0aXRpb24ubHMsIGdldF9keW4pCmBgYAoKIyBwcm9jZXNzIGRhdGFmcmFtZQpgYGB7cn0KIyBpbXBvcnQgaW4gZGF0YWZyYW1lCm5vX1cubHMgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9keW4vIiksIHBhdHRlcm4gPSAiKm5vV19keW4ucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpub19XLmRmIDwtIGxhcHBseShub19XLmxzLCByZWFkX3BhcnF1ZXQpCm5vX1cuZGYgPC0gZG8uY2FsbChyYmluZCwgbm9fVy5kZikKCiMgY29tYmluZSB3aXRoIGV6IGxhYmVsCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCm5vX1cuZGYgPC0gbGVmdF9qb2luKG5vX1cuZGYsIGV6X2xhYmVsLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQoKIyBnZXQgY29udmVyc2lvbiByYXRlIApub19XLmNyIDwtIG5vX1cuZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKQpub19XLkkgPC0gbm9fVy5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIikKCiMgZ2V0IGRlZmF1bHQgY29udmVyc2lvbiByYXRlIGR5bmFtaWNzCnNpX2R5bi5kZiA8LSBsZWZ0X2pvaW4oc2lfZHluLmRmLCBlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKc2lfZHluLmNyIDwtIHNpX2R5bi5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpCnNpX2R5bi5JIDwtIHNpX2R5bi5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIikKYGBgCgojIHBsb3QgY29udmVyc2lvbiByYXRlCm1lY2hhbmlzbTogdGFyZ2V0ZWQgaW1tdW5pdHkgbGVkIHRvIGxvd2VyIHBhcmFzaXRlIGRlbnNpdHkgaW4gdGhlIGluaXRpYWwgc3RhZ2VzLCB3aGljaCBwcmV2ZW50cyBwYXJhc2l0ZXMgZnJvbSBtYWtpbmcgdGhlIHN3aXRjaCBmcm9tIG5vIGNvbnZlcnNpb24gcmF0ZSB0byBoaWdoIGNvbnZlcnNpb24gcmF0ZS4gV2hlbiBwYXJzaXRlIGRlbnNpdHkgdW5kZXJnb2VzIGRyYXN0aWMgaW5jcmVhc2UgYXQgdGhlIGJlZ2lubmluZyBkdWUgdG8gbG93ZXIgaW1tdW5pdHksIHRoaXMgcHJlc2VudHMgYSBoaWdoZXIgZGVncmVlIG9mIHNpZ25hbCB0aGF0IGFsbG93cyBwYXJhc2l0ZSB0byBtYWtlIHRoZSBzd2l0Y2ggYXBwcm9wcmlhdGVseQpgYGB7cn0KcGFydGl0aW9uX2NyLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IG5vX1cuY3IsIGFlcyh4ID0gdGltZSwgeT0gdmFsdWUsIGNvbG9yID0gIk5vIHRhcmdldGVkIGltbXVuaXR5IikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHNpX2R5bi5jciwgYWVzKHggPSB0aW1lLCB5PSB2YWx1ZSwgY29sb3IgPSAiRGVmYXVsdCIpKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWxfc2ksIG5jb2wgPSA1KSArCiAgeGxpbSgwLCAyMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDcpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIGNvbG9yID0gIkNvbmRpdGlvbiIpICsKICB0aGVtZV9idygpCgpub19XLmNyCmBgYAoKIy0tLS0tIGN1ZSBzdGF0ZSAtLS0tLS0tLS0tLS0tLSMKCiMgZnVuY3Rpb24gdG8gZ2V0IGN1ZSBzdGF0ZXMKYGBge3J9CiMgZnVuY3Rpb24gdG8gZ2V0IGN1ZSBzdGF0ZXMKZ2V0X2N1ZV9zdGF0ZSA8LSBmdW5jdGlvbihkZil7CiAgY3VlIDwtIHRyaW13cyhnc3ViKCJfbG9nfF9ub25lIiwgIiIsIHVuaXF1ZShkZiRpZCkpKQogIGlmKGN1ZSAhPSAiSStJZyIpewogIGRmMiA8LSBkZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09IGN1ZSkKICBpZihzdHJfZGV0ZWN0KHVuaXF1ZShkZiRpZCksICJsb2ciKSl7CiAgICBkZjIgPC0gZGYyICU+JSAKICAgICAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKQogIH0KICB9CiAgCiAgaWYoY3VlID09ICJJK0lnIil7CiAgICBkZjIgPC0gZGYgJT4lIGZpbHRlcih2YXJpYWJsZSAlaW4lIGMoIkkiLCAiSWciKSkgJT4lIAogICAgICBncm91cF9ieSh0aW1lKSAlPiUgCiAgICAgIG11dGF0ZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpCiAgICAKICAgIGlmKHN0cl9kZXRlY3QodW5pcXVlKGRmJGlkKSwgImxvZyIpKXsKICAgIGRmMiA8LSBkZjIgJT4lIAogICAgICBtdXRhdGUodmFsdWUgPSBsb2cxMCh2YWx1ZSkpCiAgfQogIH0KICAKICBkZjIkdmFsdWVbZGYyJHZhbHVlID09IC1JbmZdIDwtIDAKICAKICB3cml0ZV9wYXJxdWV0KGRmMiwgcGFzdGUwKGhlcmUoImRhdGEvcGFydGl0aW9uL3NpX2RlZmF1bHRfc3RhdGUvIiksIHVuaXF1ZShkZiRpZCksICJfbm9XX3N0YXRlLnBhcnF1ZXQiKSkKfQpgYGAKCiMgcnVuIGZ1bmN0aW9uCmBgYHtyfQojIHNwbGl0IGR5bmFtaWNzIGJhc2VkIG9uIGlkCm5vX1cuc3BsaXQgPC0gc3BsaXQobm9fVy5kZiwgbm9fVy5kZiRpZCkKCiMgcnVuIGZ1bmN0aW9uCm1jbGFwcGx5KG5vX1cuc3BsaXQsIGdldF9jdWVfc3RhdGUpCgojIGdldCBkYXRhZnJhbWUKbm9fVy5zdGF0ZSA8LSBsaXN0LmZpbGVzKGhlcmUoImRhdGEvcGFydGl0aW9uL3NpX3N0YXRlLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpub19XLnN0YXRlIDwtIGxhcHBseShub19XLnN0YXRlLCByZWFkX3BhcnF1ZXQpCm5vX1cuc3RhdGUgPC0gZG8uY2FsbChyYmluZCwgbm9fVy5zdGF0ZSkKbm9fVy5zdGF0ZSR2YWx1ZVtub19XLnN0YXRlJHZhbHVlIDwgMF0gPC0gMAoKIyBnZXQgc2FtZSBmb3Igc2kgaW5mZWN0aW9uCmRlZmF1bHQuc3BsaXQgPC0gc3BsaXQoc2lfZHluLmRmLCBzaV9keW4uZGYkaWQpCm1jbGFwcGx5KGRlZmF1bHQuc3BsaXQsIGdldF9jdWVfc3RhdGUpCmRlZmF1bHQuc3RhdGUgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9kZWZhdWx0X3N0YXRlLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpkZWZhdWx0LnN0YXRlIDwtIGxhcHBseShkZWZhdWx0LnN0YXRlLCByZWFkX3BhcnF1ZXQpCmRlZmF1bHQuc3RhdGUgPC0gZG8uY2FsbChyYmluZCwgZGVmYXVsdC5zdGF0ZSkKZGVmYXVsdC5zdGF0ZSR2YWx1ZVtkZWZhdWx0LnN0YXRlJHZhbHVlIDwgMF0gPC0gMAoKIyBtYW51YWxseSBjb3JyZWN0IG5vbi1sb2dnaW5nCklfSWcuY29yciA8LSBub19XLnN0YXRlICU+JSBmaWx0ZXIoaWQgPT0gIkkrSWdfbG9nIikgJT4lIAogIG11dGF0ZSh2YWx1ZSA9IGxvZzEwKHZhbHVlKSkKSV9JZy5jb3JyJHZhbHVlW0lfSWcuY29yciR2YWx1ZSA8IDBdIDwtIDAKCm5vX1cuc3RhdGUyIDwtIG5vX1cuc3RhdGUgJT4lIGZpbHRlcihpZCAhPSAiSStJZ19sb2ciKQpub19XLnN0YXRlMiA8LSBub19XLnN0YXRlMiAlPiUgcmJpbmQobm9fVy5zdGF0ZTIsIElfSWcuY29ycikKYGBgCgojIHBsb3QKYWJzZW5jZSBvZiB0YXJnZXRlZCBpbW11bml0eSBsZWQgdG8gZHJhc3RpYyBpbmNyZWFzZSBpbiBwYXJhc2l0ZSBkZW5zaXR5IGluIGVhcmx5IHBoYXNlcyBvZiBpbmZlY3Rpb24uIFRoaXMgcHJvZHVjZXMgaGlnaCBzaWduYWwgaW50ZW5zaXR5IGZvciBwYXJhc2l0ZSBhbmQgaG9zdC1iYXNlZCBjdWVzLCBlc3BlY2lhbGx5IG5vbi1sb2dnZWQgb25lcywgd2hpY2ggYWxsb3dzIGZvciBzdGF0ZSBkaWZmZXJlbnRhdGlvbi4gV2hpbGUgdGhpcyBjYW4gYmUgdmlld2VkIGFzIGEgbW9kZWxsaW5nIGFydGlmaWFjdCwgaXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgdGhlIGxvZ2dlZCBjdWVzIHNlbGRvbSBjaGFuZ2VkIGFzIHRoZXNlIGNoYW5nZXMgaW4gZWFybHkgaW5mZWN0aW9uIGRpZCBsaXR0bGUgdG8gYWx0ZXIgdGhlIGFjdHVhbCBlYXJseSBzaWduYWwgaW50ZW5zaXR5IHNlbnNlZCBieSB0aGUgcGFyYXNpdGUuIEluIGFuIGVudmlyb25tZW50IHdoZXJlIHRoZXJlIGlzIGhldGVyb2dlbmVpdHkgaW4gaG9zdCByZXNwb25zZSwgYW5kIHRodXMsIHNpZ25hbCwgbG9nZ2luZyBhbGxvd3MgZm9yIHBhcmFzaXRlcyB0byBhZGFwdCBvcHRpbWFsIHN0cmF0ZWd5IHdoZXJlYXMgbm9uLWxvZ2dlZCBjdWVzIG11c3QgY29udGVuZCB3aXRoIHNlbnNpdGl2aXR5IHRvIGltbXVuaXR5LgpgYGB7cn0KIyBmdW5jdGlvbiB0byBpbmRpdmlkdWFsbHkgcGxvdCBzdHVmZgpwbG90X3N0YXRlIDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICAjIHBsb3Qgc3RhdGUgZHluYW1pY3MKICBzdGF0ZV9wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkZjEsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLCBjb2xvciA9IG5hbWUsIGdyb3VwID0gbmFtZSkpICsKICBmYWNldF93cmFwKH5lel9sYWJlbF9zaSwgc2NhbGVzID0gImZyZWUiKSArCiAgeGxpbSgxLDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGxhYnMoeCA9ICIiLCB5ID0gIkN1ZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPWMoIkRlZmF1bHQiID0gIiM0NTc1YjQiLCAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiA9ICIjZmM4ZDU5IikpCiAgCiAgIyBwbG90IGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljcwogIGNyX3BsIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gZGYyLCBhZXMoeCA9IHRpbWUsIHkgPSBuYW1lLCBmaWxsID0gdmFsdWUpKSArCiAgeGxpbSgxLDIwKSArCiAgdGhlbWVfYncoKSArCiAgICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltID0gYygwLCAxKSkKICAKICAjIGFycmFuZ2UKICBnZ2FycmFuZ2Uoc3RhdGVfcGwsIGNyX3BsLCBuY29sID0gMSwgbnJvdyA9IDIsIGFsaWduID0gInYiLCBoZWlnaHRzID0gYygxLCAwLjQpKQogIGdnc2F2ZShwYXN0ZTAoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9wYXJ0aXRpb24vIiksIHVuaXF1ZShkZjEkaWQpLCAiLnRpZmYiKSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMuNSkKfQpgYGAKCiMgc3BsaXQKYGBge3J9CiMgY29tYmluZSBzdGF0ZQpub1dfZGVmYXVsdC5zdGF0ZSA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KG5vX1cuc3RhdGUyLCB0aW1lLCBgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCA9IHZhbHVlLCBpZCwgZXpfbGFiZWxfc2kpLCAKICBzZWxlY3QoZGVmYXVsdC5zdGF0ZSAlPiUgZmlsdGVyKHRpbWUgPD0gMjApLCB0aW1lLCBgRGVmYXVsdGAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgYnkgPSBjKCJ0aW1lIiwgImlkIiwgImV6X2xhYmVsX3NpIikpCgpub1dfZGVmYXVsdC5zdGF0ZTIgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihub1dfZGVmYXVsdC5zdGF0ZSwgYyhgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCwgYERlZmF1bHRgKSkKIyBjb21iaW5lIGNvbnZlcnNpb24gcmFzdGVyCm5vV19kZWZhdWx0LmNyIDwtIGxlZnRfam9pbigKICBzZWxlY3Qobm9fVy5jciwgdGltZSwgYE5vIHRhcmdldGVkXG5pbW11bml0eWAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgCiAgc2VsZWN0KHNpX2R5bi5jciAlPiUgZmlsdGVyKHRpbWUgPD0gMjApLCB0aW1lLCBgRGVmYXVsdGAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgYnkgPSBjKCJ0aW1lIiwgImlkIiwgImV6X2xhYmVsX3NpIikpCm5vV19kZWZhdWx0LmNyMiA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKG5vV19kZWZhdWx0LmNyLCBjKGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgLCBgRGVmYXVsdGApKQoKIyBzcGxpdApub1dfZGVmYXVsdF9zdGF0ZS5scyA8LSBzcGxpdChub1dfZGVmYXVsdC5zdGF0ZTIsIG5vV19kZWZhdWx0LnN0YXRlMiRpZCkKbm9XX2RlZmF1bHRfY3IubHMgPC0gc3BsaXQobm9XX2RlZmF1bHQuY3IyLCBub1dfZGVmYXVsdC5jcjIkaWQpCgojIHJ1biBmdW5jdGlvbgptYXBwbHkocGxvdF9zdGF0ZSwgbm9XX2RlZmF1bHRfc3RhdGUubHMsIG5vV19kZWZhdWx0X2NyLmxzKQpgYGAKCiMtLS0tLS0tLSByZWFjdGlvbiBub3JtcyBvZiBkZWZhdWx0IHZzIG9wdGltaXplZCAtLS0tLS0tLS0tLS0jCiMgZ2V0IHJlYWN0aW9uIG5vcm0gYW5kIHJ1ZyBkYXRhCmBgYHtyfQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL3Bhcl90b19kZi5SIikpCgojIEdhbWV0b2N5dGUKZ19sb2cucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMS4yMTE1MjEsCS0zLjkzNjc3OCwJLTEuMzEyOTQ0LAktMS4yODU3MTMpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgbG9nMTAoNiooMTBeNCkpLCBieSA9IChsb2cxMCg2KigxMF40KSkpLzUwMDApKQpnX2xvZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoMS4zOTM4NjA1MzksCS00LjI1MzAwNzYxNiwJLTAuMzEzOTQ3MDI5LAktMi4wMDA4NTczNDQpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgbG9nMTAoNiooMTBeNCkpLCBieSA9IChsb2cxMCg2KigxMF40KSkpLzUwMDApKQoKZy5ybiA8LSBwYXJfdG9fZGYocGFyID0gYygwLjA0MDYxMjg4LAktOS4zMTQ0NTk1OCwJNzQuMTMwMTU1MDYsCS00MzEuNTk4NDM2NCksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF40KSwgYnkgPSAoNiooMTBeNCkpLzUwMDApKQpnLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYygwLjU0MTcyOTA3MywJLTMuOTA0NjE2NDQzLAkwLjg3NDg3NDEyLAktMC42OTQxNzcwMjEpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNCksIGJ5ID0gKDYqKDEwXjQpKS81MDAwKSkKCiMgSStJZwpJX0lnX2xvZy5ybiA8LSBwYXJfdG9fZGYocGFyID0gYygzLjU5NDA0MiwJNC4xNTc3NDQsCS0xMy41MzA2NzIsCTIuNTk5OTA1KSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSkKSV9JZ19sb2cucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDYzLjcxODkzODIyLAktODcuNzc2NzE2MDEsCS01Ni41NTQ3NTUxNCwJLTY2LjAyMjA5NTQ5KSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSkKCklfSWcucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMC4zMTU5Mjk3LAktNDYuMTEwNDU1OCwJMTI1MC43NTI5MDgsCS02LjE5ODIwOTMpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNiksIGJ5ID0gKDYqKDEwXjYpKS81MDAwKSkKSV9JZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoMC43MzE5ODI3ODQsCS0yMS42OTc5OTQ0OSwJMTQ5Ljc4NDE4NzYsCTE3LjAyNTUxNzY5KSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjYpLCBieSA9ICg2KigxMF42KSkvNTAwMCkpCgojIGNvbnZlcnQgbG9nIHRvIG5vbi1sb2dnZWQgc2NhbGUKZ19sb2cucm4kY3VlX3JhbmdlIDwtIDEwXihnX2xvZy5ybiRjdWVfcmFuZ2UpCmdfbG9nLnJuMiRjdWVfcmFuZ2UgPC0gMTBeKGdfbG9nLnJuMiRjdWVfcmFuZ2UpCklfSWdfbG9nLnJuJGN1ZV9yYW5nZSA8LSAxMF4oSV9JZ19sb2cucm4kY3VlX3JhbmdlKQpJX0lnX2xvZy5ybjIkY3VlX3JhbmdlIDwtIDEwXihJX0lnX2xvZy5ybjIkY3VlX3JhbmdlKQoKIyBnZXQgcnVnCmdfbG9nLnJ1ZyA8LSBkZWZhdWx0LnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkcgbG9nIikgJT4lIAogIG11dGF0ZSh2YWx1ZSA9IDEwXnZhbHVlKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCmdfbG9nLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIGxvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSAxMF52YWx1ZSkgJT4lIAogIGZpbHRlcih2YWx1ZSA8PSA2KigxMF40KSkgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpJX0lnX2xvZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIGxvZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZ19sb2cucnVnMiA8LSBub19XLnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkkrSWcgbG9nIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnLnJ1ZyA8LSBkZWZhdWx0LnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCmcucnVnMiA8LSBub19XLnN0YXRlICU+JSAKICBmaWx0ZXIobGFiZWxfc2kgPT0gIkciICYgdmFsdWUgPD0gNiooMTBeNCkpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpJX0lnLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgojIGdldCBydWcgbGltaXRzCnJ1Z19saW0gPC0gcmJpbmQoZ19sb2cucnVnLAogICAgICAgICAgICAgICAgIGdfbG9nLnJ1ZzIsCiAgICAgICAgICAgICAgICAgSV9JZ19sb2cucnVnLAogICAgICAgICAgICAgICAgIElfSWdfbG9nLnJ1ZzIsCiAgICAgICAgICAgICAgICAgZy5ydWcsCiAgICAgICAgICAgICAgICAgZy5ydWcyLAogICAgICAgICAgICAgICAgIElfSWcucnVnLAogICAgICAgICAgICAgICAgIElfSWcucnVnMikgJT4lIAogIGdyb3VwX2J5KGxhYmVsX3NpKSAlPiUgCiAgc3VtbWFyaXplKG1heCA9IG1heChoYWJsYXI6OnModmFsdWUpLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBtaW4gPSBtaW4oaGFibGFyOjpzKHZhbHVlKSwgbmEucm0gPSBUKSkKCiMgY29tYmluZSBhbmQgZmlsdGVyCnJuIDwtIHJiaW5kKAogIGNiaW5kKGdfbG9nLnJuLCBsYWJlbF9zaSA9ICJHIGxvZyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoZ19sb2cucm4yLCBsYWJlbF9zaSA9ICJHIGxvZyIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICBjYmluZChnLnJuLCBsYWJlbF9zaSA9ICJHIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChnLnJuMiwgbGFiZWxfc2kgPSAiRyIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICBjYmluZChJX0lnX2xvZy5ybiwgbGFiZWxfc2kgPSAiSStJZyBsb2ciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKElfSWdfbG9nLnJuMiwgbGFiZWxfc2kgPSAiSStJZyBsb2ciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoSV9JZy5ybiwgbGFiZWxfc2kgPSAiSStJZyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoSV9JZy5ybjIsIGxhYmVsX3NpID0gIkkrSWciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IikKKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0sIGJ5ID0gImxhYmVsX3NpIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsX3NpKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBtYXggJiBjdWVfcmFuZ2UgPj0gbWluKQoKIyBjb21iaW5lIHJ1ZwpydWcgPC0gcmJpbmQoY2JpbmQoZ19sb2cucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoZ19sb2cucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogICAgICAgICAgICAgY2JpbmQoZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChnLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWdfbG9nLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWdfbG9nLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWcucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoSV9JZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IikpCgojIGNvYmluZSB3aXRoIGV6bGFiZWwKcm4yIDwtIHJuICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX3NpIikKcnVnMiA8LSBydWcgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSAibGFiZWxfc2kiKQoKIyBmaWx0ZXIgcnVnCmRlZmF1bHQucnVnIDwtIHJ1ZzIgJT4lIGZpbHRlcihjb25kaXRpb24gPT0gIkRlZmF1bHQiKQpuby5ydWcgPC0gcnVnMiAlPiUgZmlsdGVyKGNvbmRpdGlvbiA9PSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IikKYGBgCgojIHBsb3QKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IHJuMiwgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9ydWcoZGF0YSA9IGRlZmF1bHQucnVnLCBhZXMoeCA9IHZhbHVlLCBjb2xvciA9IGNvbmRpdGlvbiksIHNpZGVzID0gImIiKSArCiAgZ2VvbV9ydWcoZGF0YSA9IG5vLnJ1ZywgYWVzKHggPSB2YWx1ZSwgY29sb3IgPSBjb25kaXRpb24pLCBzaWRlcyA9ICJ0IikgKwogIGZhY2V0X3dyYXAofmZjdF9yZWxldmVsKGV6X2xhYmVsX3NpLCBjKCJHYW1ldG9jeXRlIGxvZzEwIiwgIkdhbWV0b2N5dGUiLCAiQXNleHVhbCZzZXh1YWxcbmlSQkMgbG9nMTAiLCAiQXNleHVhbCZzZXh1YWwgaVJCQyIpKSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPWMoIkRlZmF1bHQiID0gIiM0NTc1YjQiLCAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiA9ICIjZmM4ZDU5IikpICsKICB5bGltKDAsIDEuMSkgKwogIGxhYnMoeCA9ICJDdWUgcmFuZ2UiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIGNvbG9yID0gIkNvbmRpdGlvbiIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9wYXJ0aXRpb25fcm4udGlmZiIpLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0gNikKYGBgCgojIGdldCBjb252ZXJzaW9uIHJhdGUgbGVnZW5kCmBgYHtyfQpub1dfZGVmYXVsdC5jciAlPiUgZmlsdGVyKGlkID09ICJHX2xvZyIpICU+JSAKZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGFlcyh4ID0gdGltZSwgeSA9IGlkLCBmaWxsID0gRGVmYXVsdCkpICsKICB4bGltKDEsMjApICsKICB0aGVtZV9idygpICsKICAgIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsCiAgICAgICAgIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbSA9IGMoMCwgMSkpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9jcl9sZWdlbmQudGlmZiIpKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBEaXNlYXNlIGN1cnZlcyBmb3Igc2luZ2xlLCBjby1pbmZlY3Rpb24sIGFuZCBpbnZhc2lvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBnZXQgZGF0YSBmb3IgZGlzZWFzZSBjdXJ2ZXMKYGBge3J9CiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljcwpzaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvc2lfZHluL3NpX2R5bl8zMC5wYXJxdWV0IikpIAoKIyBjby1pbmZlY3Rpb24gZHluYW1pY3MgKG1vbi1jdWUpCmNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfZHluLnBhcnF1ZXQiKSkKCiMgZHVhbCBjdWUgZHluYW1pY3MKZHVhbF9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZHVhbF9jdWVfZHluL2R1YWxfY3VlX2R5bi5wYXJxdWV0IikpCmBgYAoKIy0tLS0tLS0gc2luZ2xlIGN1ZSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgZ2V0IGNsYXNzaWZpY2F0aW9uCnNpX2N1ZS5kdiA8LSBzaV9maXRuZXNzLmRmICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBjYXNlX3doZW4oCiAgICB2YWx1ZSA+IDkuMiB+ICJIaWdoLXBlcmZvcm1pbmciLAogICAgdmFsdWUgPD0gOS4yIH4gIlBvb3ItcGVyZm9ybWluZyIKICApKQoKIyBwcm9jZXNzIGR5bmFtaWNzIC0+IHR1cm4gc2tpbm55CnNpX2RjLmRmIDwtIHNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJJIiB8IHZhcmlhYmxlID09ICJJZyIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUgCiAgbXV0YXRlKHRvdGFsID0gSStJZykKCiMgam9pbiB3aXRoIGNsYXNzaWZpY2FpdG9uCnNpX2RjLmRmMiA8LSBzaV9kYy5kZiAlPiUgbGVmdF9qb2luKHNlbGVjdChzaV9jdWUuZHYsIGlkLCBjbGFzc2lmaWNhdGlvbiksIGJ5ID0gImlkIikKc2lfY3VlLmR2CiMgc3BsaXQgaW50byB0b3AgZXJmb3JtaW5nIGFuZCBwb29yLXBlcmZvcm1pbmcgY3VlcwpzaV9kYy5oaWdoIDwtIHNpX2RjLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJIaWdoLXBlcmZvcm1pbmciKQpzaV9kYy5wb29yIDwtIHNpX2RjLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJQb29yLXBlcmZvcm1pbmciKQoKIyBqb2luIGhpZ2ggcGVyZm9ybWluZyB3aXRoIGxhYmVsCnNpX2RjLmhpZ2ggPC0gc2lfZGMuaGlnaCAlPiUgbGVmdF9qb2luKGV6X2xhYmVsICU+JSBkaXN0aW5jdChsYWJlbF9zaSwgLmtlZXBfYWxsID0gVCksIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCgojd3JpdGVfcGFycXVldChzaV9kYy5oaWdoLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfaGlnaC5wYXJxdWV0IikpCiN3cml0ZV9wYXJxdWV0KHNpX2RjLnBvb3IsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19wb29yLnBhcnF1ZXQiKSkKYGBgCgojIHBsb3QKYGBge3J9CnNpX2RjLnBvb3IgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19wb29yLnBhcnF1ZXQiKSkKc2lfZGMuaGlnaCA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX2hpZ2gucGFycXVldCIpKQoKIyBwbG90CnNpX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzaV9kYy5wb29yLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGlkKSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uXG5nb29kIHBlcmZvcm1pbmcgY3VlcyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKc2lfZGMucGwgPC0gc2lfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9kYy5oaWdoICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0wKSwgYWVzKHggPSB0b3RhbCwgeSA9IFIsIGNvbG9yID0gZXpfbGFiZWwsIHNoYXBlID0gZXpfbGFiZWwpLCBzaXplID0gMykgKwogIGdlb21fcGF0aChkYXRhID0gc2lfZGMuaGlnaCwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBlel9sYWJlbCwgY29sb3IgPSBlel9sYWJlbCksIHNpemUgPSAxLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICIjNDU3NWI0IiwgIiNmYzhkNTkiLCAiI2ZkY2I0NCIsICIjOTFiZmRiIikpICArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFKSkKYGBgCgojLS0tLS0tLS0tLSBjby1pbmZlY3Rpb24gbW9ub2N1ZSAtLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBnZXQgcmVsZXZlbnQgdmFyaWFibGVzCmNpX2RjLmRmIDwtIGNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJJMSIgfCB2YXJpYWJsZSA9PSAiSWcxIiB8IHZhcmlhYmxlID09ICJSIikKCiMgbW9ycGggaW50byBza2lubnkgZm9ybWF0CmNpX2RjLmRmIDwtIHRpZHlyOjpwaXZvdF93aWRlcihjaV9kYy5kZiwgbmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBsYWJlbCkpICU+JSAKICBtdXRhdGUodG90YWwgPSBJMStJZzEpCgojIGdvb2QgY3VlIGJhZCBjdWUKY2lfY3VlLmR2IDwtIGNpX2ZpdG5lc3MuZGYgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIHZhbHVlID4gMi4yNSB+ICJIaWdoLXBlcmZvcm1pbmciLAogICAgdmFsdWUgPD0gMi4yNSB+ICJQb29yLXBlcmZvcm1pbmciCiAgKSkKCiMgam9pbiB3aXRoIGNsYXNzaWZpY2FpdG9uCmNpX2RjLmRmMiA8LSBjaV9kYy5kZiAlPiUgbGVmdF9qb2luKGNpX2N1ZS5kdiwgYnkgPSAibGFiZWwiKQoKIyBzcGxpdCBpbnRvIHRvcCBlcmZvcm1pbmcgYW5kIHBvb3ItcGVyZm9ybWluZyBjdWVzCmNpX2RjLmhpZ2ggPC0gY2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIkhpZ2gtcGVyZm9ybWluZyIpCmNpX2RjLnBvb3IgPC0gY2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIlBvb3ItcGVyZm9ybWluZyIpCgojIGpvaW4gaGlnaCBwZXJmb3JtaW5nIHdpdGggbGFiZWwKY2lfZGMuaGlnaDIgPC0gY2lfZGMuaGlnaCAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9jaSIpKQoKI3dyaXRlX3BhcnF1ZXQoY2lfZGMuaGlnaDIsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9kY19oaWdoLnBhcnF1ZXQiKSkKI3dyaXRlX3BhcnF1ZXQoY2lfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX3Bvb3IucGFycXVldCIpKQpgYGAKCiMgcGxvdApgYGB7cn0KY2lfZGMucG9vciA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX3Bvb3IucGFycXVldCIpKQpjaV9kYy5oaWdoMiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX2hpZ2gucGFycXVldCIpKQoKIyBwbG90CmNpX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBjaV9kYy5wb29yLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGxhYmVsKSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJDby1pbmZlY3Rpb25cbmdvb2QgcGVyZm9ybWluZyBjdWVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiKSArCiAgdGhlbWVfYncoKSsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKSArCiAgZ3VpZGVzKHNoYXBlID0gRkFMU0UpCgpjaV9kYy5wbCA8LSBjaV9kYy5wcmUgKwogIGdlb21fcG9pbnQoZGF0YSA9IGNpX2RjLmhpZ2gyICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0wKSwgYWVzKHggPSB0b3RhbCwgeSA9IFIsIGNvbG9yID0gZXpfbGFiZWwsIHNoYXBlID0gZXpfbGFiZWwpLCBzaXplID0gMykgKwogIGdlb21fcGF0aChkYXRhID0gY2lfZGMuaGlnaDIsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gZXpfbGFiZWwsIGNvbG9yID0gZXpfbGFiZWwpLCBzaXplID0gMSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzQ1NzViNCIsICIjZmM4ZDU5IiwgIiNmZGNiNDQiLCAiIzkxYmZkYiIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFKSkKCmBgYAoKIy0tLS0tLS0tLSBkdWFsIGN1ZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgdHVybiBza2lubnkKZHVhbF9kYy5kZiA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IHBhc3RlKGxhYmVsLCAiKyIgLCBsYWJlbF9iKSkgJT4lIAogIHNlbGVjdChsYWJlbF9hbHQsIHRpbWUsIHZhcmlhYmxlLCB2YWx1ZSkgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIgfCB2YXJpYWJsZSA9PSAiSWciIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgZGlzdGluY3QobGFiZWxfYWx0LCB0aW1lLCB2YXJpYWJsZSwgLmtlZXBfYWxsID0gVCkKCmR1YWxfZHluLmRmCgpkdWFsX2RjLmRmMiA8LSBkdWFsX2RjLmRmICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBsYWJlbF9hbHQpKSAlPiUKICBtdXRhdGUodG90YWwgPSBJK0lnKQoKd3JpdGVfcGFycXVldChkdWFsX2RjLmRmMiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGMucGFycXVldCIpKQoKIyBnb29kIGR1YWwgY3VlIC0+IGxpc3Qgb2YgZ29vZCBwZXJmb3JtaW5nIGR1YWwgY3VlcyB0aGF0IGVuY29tcGFzcyB3aWRlIHZhcmlldHkgb2YgY3VlcwpzZWxlY3RlZF9kdWFsX2N1ZSA8LSBjKCJSIGxvZyArIEkgbG9nIiwgIlIgKyBJZyBsb2ciLCAiRyBsb2cgKyBJIGxvZyIsICJHIGxvZyArIElnIGxvZyIsICJJZyArIEkgbG9nIikKYmFkX2R1YWxfY3VlIDwtIGMoIkcgKyBJIiwgIlIgKyBJZyIsICJSIGxvZyArIElnIiwgIkcgKyBSIiwgIkcgKyBSIGxvZyIsICJHICsgSWciLCAiSWcgKyBJIiwgIlIgKyBJIiwgIlIgbG9nICsgSSIpCgojIGdldCBjbGFzc2lmaWNhdGlvbiAtPiBSIGxvZzEwICsgSSBsb2cxMCBhcyB0aGUgb25seSBnb29kIG9uZQpkdWFsX2RjLmhpZ2ggPC0gZHVhbF9kYy5kZjIgJT4lIGZpbHRlcihsYWJlbF9hbHQgJWluJSBzZWxlY3RlZF9kdWFsX2N1ZSkgJT4lIAogIG11dGF0ZShsYWJlbF9hbHQgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9hbHQpKQpkdWFsX2RjLnBvb3IgPC0gZHVhbF9kYy5kZjIgJT4lIGZpbHRlcihsYWJlbF9hbHQgJWluJSBiYWRfZHVhbF9jdWUpICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYWx0KSkKI3dyaXRlX3BhcnF1ZXQoZHVhbF9kYy5oaWdoLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19oaWdoLnBhcnF1ZXQiKSkKI3dyaXRlX3BhcnF1ZXQoZHVhbF9kYy5wb29yLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19wb29yLnBhcnF1ZXQiKSkKCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX2RjLmhpZ2ggPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjX2hpZ2gucGFycXVldCIpKQpkdWFsX2RjLnBvb3IgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjX3Bvb3IucGFycXVldCIpKQoKZHVhbF9kYy5oaWdoMiA8LSBkdWFsX2RjLmhpZ2ggJT4lIAogIGZpbHRlcihsYWJlbF9hbHQgPT0gIlIgbG9nMTAgKyBJIGxvZzEwIikKCiMgYWRkIApkdWFsX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkdWFsX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gbGFiZWxfYWx0KSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJIaWdoLXBlcmZvcm1pbmdcbmR1YWwgY3VlcyBwZXIgwrVMIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiLCB5ID0gIlJCQyBwZXIgwrVMIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKCmR1YWxfZGMucGwgPC0gZHVhbF9kYy5wcmUgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfZGMuaGlnaDIgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PTApLCBhZXMoeCA9IHRvdGFsLCB5ID0gUiwgc2hhcGUgPSBsYWJlbF9hbHQpLCBjb2xvciA9ICIjNDU3NWI0Iiwgc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfZGMuaGlnaDIsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gbGFiZWxfYWx0KSwgY29sb3IgPSAiIzQ1NzViNCIsIHNpemUgPSAxLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC4xKSkpCmBgYAoKIy0tLS0tLS0tLSBjby1pbmZlY3Rpb24gc3RhdGljIC0tLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGltcG9ydCBpbiBkeW5hbWljcyBkYXRhCnN0YXRpY19keW4ubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV9zdGF0aWMvIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCnN0YXRpY19keW4ubHMgPC0gbGFwcGx5KHN0YXRpY19keW4ubHMsIHJlYWRfcGFycXVldCkKCiMgZmlsdGVyIHZhcmlhYmxlIGFuZCB0cmFuc2Zvcm0Kc3RhdGljX2R5bi5sczIgPC0gbWNsYXBwbHkoc3RhdGljX2R5bi5scywgZnVuY3Rpb24oeCl7CiAgeCAlPiUgCiAgICBmaWx0ZXIodmFyaWFibGUgPT0gIkkxIiB8IHZhcmlhYmxlID09ICJJZzEiIHwgdmFyaWFibGUgPT0gIkkyIiB8IHZhcmlhYmxlID09ICJJZzIiIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgICBtdXRhdGUoaWRfYWx0ID0gcGFzdGUoaWRfMSwgaWRfMikpICU+JSAKICAgIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGlkX2FsdCkpICU+JQogIG11dGF0ZSh0b3RhbDEgPSBJMStJZzEsIHRvdGFsMiA9IEkyK0lnMikKfSkKCnN0YXRpY19kYy5kZiA8LSBkby5jYWxsKHJiaW5kLCBzdGF0aWNfZHluLmxzMikKc3RhdGljX2RjLmRmIDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbXV0YXRlKGlkXzEgPSBnc3ViKCIgLioiLCAiIiwgaWRfYWx0KSwKICAgICAgICAgaWRfMiA9IGdzdWIoIi4qICIsICIiLCBpZF9hbHQpKSAlPiUgCiAgZmlsdGVyKGlkXzEgIT0gaWRfMikKI3dyaXRlX3BhcnF1ZXQoc3RhdGljX2RjLmRmLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc3RhdGljX2RjLnBhcnF1ZXQiKSkKYGBgCgojIGZ1cnRoZXIgcHJvY2Vzc2luZwpgYGB7cn0Kc3RhdGljX2RjLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc3RhdGljX2RjLnBhcnF1ZXQiKSkKIyBnZXQgd2lubmVycyBhbmQgbG9zZXJzCiMjIGltcG9ydCBpbiBmaXRuZXNzCnN0YXRpY19maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQojIyBnZXQgd2lubmVyIHNpdHVhdGlvbgpzdGF0aWNfZml0bmVzcy5kZjIgPC0gc3RhdGljX2ZpdG5lc3MuZGYgJT4lIAogIGZpbHRlcihpZF8xICE9IGlkXzIpICU+JSAKICBtdXRhdGUod2lubmluZ19pZCA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiBpZF8xLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gaWRfMgogICksCiAgbG9zaW5nX2lkID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlIDwgMCB+IGlkXzEsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U+IDAgfiBpZF8yCiAgKSkKCiMgbGVmdCBqb2luCnN0YXRpY19kYy5kZjIgPC0gc3RhdGljX2RjLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHN0YXRpY19maXRuZXNzLmRmMiwgaWRfMSwgaWRfMiwgd2lubmluZ19pZCwgbG9zaW5nX2lkLCBmaXRuZXNzX2RpZmZlcmVuY2UpLCBieSA9IGMoImlkXzEiLCAiaWRfMiIpKQoKIyBnZXQgd2lubmVyLWxvc2VyIGRpZmZlcmVuY2UgaW4gdGVybXMgb2YgSStJZyBhbHNvIGZpbHRlciBvdXQgdG8gb255bCB2ZXJ5IHN0cm9uZyBmaXRuZXNzIGRpZmZlcmVuY2UKc3RhdGljX2RjLmRmMyA8LSBzdGF0aWNfZGMuZGYyICU+JSAKICBtdXRhdGUodG90YWxfZGlmZiA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDEtdG90YWwyLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwyLXRvdGFsMgogICksCiAgdG90YWxfd2lubmVyID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMSwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwyLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwxCiAgKSkgJT4lIAogIGZpbHRlcihhYnMoZml0bmVzc19kaWZmZXJlbmNlKSA+IDAuNSkKYGBgCgojIHBsb3QKYGBge3J9CnN0YXRpY19kYy5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzdGF0aWNfZGMuZGYzLCBhZXMoeD0gdG90YWxfd2lubmVyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIldpbm5lciIpLCBhbHBoYSA9IDAuNSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzdGF0aWNfZGMuZGYzLCBhZXMoeD0gdG90YWxfbG9zZXIsIHkgPSBSLCBncm91cCA9IGlkX2FsdCwgY29sb3IgPSAiTG9zZXIiKSwKICAgICAgICAgIGFscGhhID0gMC41LGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGxhYnMoY29sb3IgPSAiU3RhdHVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiLCB5ID0gIlJCQyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIldpbm5lciIgPSAiIzQ1NzViNCIsIkxvc2VyIj0gIiNmYzhkNTkiKSkgICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKQpgYGAKCgojLS0tLS0tLS0tY28taW5mZWN0aW9uIGludmFzaW9uIC0tLS0tLS0tLS0tLS0tLSMKIyBnZXQgaW52YXNpb24gZHluYW1pYwpgYGB7cn0KIyBnZXQgaW52YXNpb24gZGYKaW52YXNpb25fZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQoKIyBnZXQgY3VlIHJhbmdlCmNpX2N1ZV9yYW5nZSA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2N1ZV9yYW5nZV9jaS5jc3YiKSkKaW52YXNpb25fZml0bmVzcy5kZjIgPC0gaW52YXNpb25fZml0bmVzcy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChjaV9jdWVfcmFuZ2UsIGlkLCBtdXRfY3VlID0gY3VlLCBtdXRfbG93ID0gbG93LCBtdXRfaGlnaCA9IGhpZ2gsIG11dF9ieSA9IGJ5KSwgYnkgPSBjKCJtdXRfaWQiPSAiaWQiKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfY3VlX3JhbmdlLCBpZCwgcmVzX2N1ZSA9IGN1ZSwgcmVzX2xvdyA9IGxvdywgcmVzX2hpZ2ggPSBoaWdoLCByZXNfYnkgPSBieSksIGJ5ID0gYygicmVzX2lkIj0gImlkIikpCmBgYAoKIyBmdW5jdGlvbiB0byBnZXQgZHluYW1pYwpgYGB7cn0KZ2V0X2ludmFzaW9uX2R5biA8LSBmdW5jdGlvbihkZil7CiAgIyBnZXQgY3VlcwogIG11dF9jdWUgPC0gZGYkbXV0X2N1ZQogIHJlc19jdWUgPC0gZGYkcmVzX2N1ZQogIAogICMgZ2V0IGluZm8gb2YgY3VlcyAoZm9yIGNvIGluZmVjdGlvbikKICBpZihzdHJpbmdyOjpzdHJfZGV0ZWN0KG11dF9jdWUsICItaSIpKXttdXRfY3VlID0gZ3N1YigiKi1pIiwgIjEiLCBtdXRfY3VlKX0KICBpZihzdHJpbmdyOjpzdHJfZGV0ZWN0KG11dF9jdWUsICItaSIsIG5lZ2F0ZSA9IFQpKXttdXRfY3VlID0gbXV0X2N1ZX0KICBpZihzdHJpbmdyOjpzdHJfZGV0ZWN0KHJlc19jdWUsICItaSIpKXtyZXNfY3VlID0gZ3N1YigiKi1pIiwgIjIiLCByZXNfY3VlKX0KICBpZihzdHJpbmdyOjpzdHJfZGV0ZWN0KHJlc19jdWUsICItaSIsIG5lZ2F0ZSA9IFQpKXtyZXNfY3VlID0gcmVzX2N1ZX0KICAKICAjIGdldCBsb2cKICBtdXRfbG9nIDwtIGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KGRmJG11dF9pZCwgImxvZyIpLCAibG9nMTAiLCAibm9uZSIpCiAgcmVzX2xvZyA8LSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChkZiRyZXNfaWQsICJsb2ciKSwgImxvZzEwIiwgIm5vbmUiKQogIAogICMgZ2V0IHBhcmFtZXRlcnMKICBtdXRfcGFyIDwtIGMoZGYkbXV0X3ZhcjFfb3B0LCBkZiRtdXRfdmFyMl9vcHQsIGRmJG11dF92YXIzX29wdCwgZGYkbXV0X3ZhcjRfb3B0KQogIHJlc19wYXIgPC0gYyhkZiRyZXNfdmFyMSwgZGYkcmVzX3ZhcjIsIGRmJHJlc192YXIzLCBkZiRyZXNfdmFyNCkKICAKICAjIGdldCBjdWUgcmFuZ2UKICBtdXRfY3VlX3JhbmdlIDwtIHNlcShkZiRtdXRfbG93LCBkZiRtdXRfaGlnaCwgYnkgPSBkZiRtdXRfYnkpCiAgcmVzX2N1ZV9yYW5nZSA8LSBzZXEoZGYkcmVzX2xvdywgZGYkcmVzX2hpZ2gsIGJ5ID0gZGYkcmVzX2J5KQogIAogICMgZ2V0IGR5bmFtaWNzIG9mIGNvIGluZmVjdGlvbgogIGNpX2R5biA8LSBjaGFiYXVkaV9jaV9jbGVhbigKICAgIHBhcmFtZXRlcnNfY3JfMSA9IG11dF9wYXIsCiAgICBwYXJhbWV0ZXJzX2NyXzIgPSByZXNfcGFyLAogICAgICAgICAgICAgICAgICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgICAgICAgICAgICAgICBjdWVfMSA9IG11dF9jdWUsCiAgICAgICAgICAgICAgICAgIGN1ZV8yID0gcmVzX2N1ZSwKICAgICAgICAgICAgICAgICAgY3VlX3JhbmdlXzEgPSBtdXRfY3VlX3JhbmdlLAogICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8yID0gcmVzX2N1ZV9yYW5nZSwKICAgICAgICAgICAgICAgIGxvZ19jdWVfMSA9IG11dF9sb2csCiAgICAgICAgICAgICAgICBsb2dfY3VlXzIgPSByZXNfbG9nLAogICAgICAgICAgICAgICAgc29sdmVyID0gInZvZGUiLAogICAgICAgICAgICAgICAgdGltZV9yYW5nZSA9IHNlcSgwLCAzMCwgMC4wMDEpLAogICAgZHluID0gVCkKICAKICAjIGFwcGVuZCBsYWJlbCB0byBhbGwgZGYKIGNpX2R5bjIgPC0gY2JpbmQoY2lfZHluLCBtdXRfaWQgPSBkZiRtdXRfaWQsIHJlc19pZCA9IGRmJHJlc19pZCkKICAKICAjIHdyaXRlCiB3cml0ZV9wYXJxdWV0KGNpX2R5bjIsIHBhc3RlMChoZXJlKCJkYXRhL2NpX2ludmFzaW9uX2R5bi8iKSwgZGYkbXV0X2lkLCAiLSIsIGRmJHJlc19pZCwgIi5wYXJxdWV0IikpCn0KYGBgCgoKIyBydW4gZHluYW1pYyBmdW5jaXRvbgpgYGB7cn0KIyBnZXQgZnVuY3Rpb24gYW5kIHBhcmFtZXRlcnMKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9jaV9jbGVhbi5SIikpCnBhcmFtZXRlcnNfdHN1a3VzaGkgPC0gYyhSMSA9IDguODkqKDEwXjYpLCAjIHNsaWdodGx5IGhpZ2hlcgogICAgICAgICAgICAgICAgbGFtYmRhID0gMy43KigxMF41KSwKICAgICAgICAgICAgICAgIG11ID0gMC4wMjUsIAogICAgICAgICAgICAgICAgcCA9IDgqKDEwXi02KSwgIyBkb3VibGVkIGZvcm0gb3JpZ2luYWwKICAgICAgICAgICAgICAgIGFscGhhID0gMSwgCiAgICAgICAgICAgICAgICBhbHBoYWcgPSAyLCAKICAgICAgICAgICAgICAgIGJldGEgPSA1LjcyMSwgCiAgICAgICAgICAgICAgICBtdW0gPSA0OCwgCiAgICAgICAgICAgICAgICBtdWcgPSA0LCAKICAgICAgICAgICAgICAgIEkwID0gNDMuODU5NjUsIAogICAgICAgICAgICAgICAgSWcwID0gMCwgCiAgICAgICAgICAgICAgICBhID0gMTUwLCAKICAgICAgICAgICAgICAgIGIgPSAxMDAsIAogICAgICAgICAgICAgICAgc3AgPSAxLAogICAgICAgICAgICAgICAgcHNpbiA9IDE2LjY5MjM0LAogICAgICAgICAgICAgICAgcHNpdyA9IDAuODQzMTc4NSwKICAgICAgICAgICAgICAgIHBoaW4gPSAwLjAzNTIwNTkxLCAKICAgICAgICAgICAgICAgIHBoaXcgPSA1NTAuODQyLAogICAgICAgICAgICAgICAgaW90YSA9IDIuMTgqKDEwXjYpLAogICAgICAgICAgICAgICAgcmhvID0gMC4yNjI3MTU2KQojIHNwbGl0CmludmFzaW9uLmxzIDwtIHNwbGl0KGludmFzaW9uX2ZpdG5lc3MuZGYyLCBzZXEobnJvdyhpbnZhc2lvbl9maXRuZXNzLmRmMikpKQoKIyBydW4gZnVuY3Rpb24KbWNsYXBwbHkoaW52YXNpb24ubHMsIGdldF9pbnZhc2lvbl9keW4sIG1jLmNvcmVzID0gNCkKYGBgCgoKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGludmFzaW9uIGR5bmFtaWNzCmludmFzaW9uX2R5bi5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL2NpX2ludmFzaW9uX2R5biIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQppbnZhc2lvbl9keW4ubHMgPC0gbGFwcGx5KGludmFzaW9uX2R5bi5scywgcmVhZF9wYXJxdWV0KQoKIyBmaWx0ZXIgYW5kIHNvIG9uCmludmFzaW9uX2R5bi5sczIgPC0gbWNsYXBwbHkoaW52YXNpb25fZHluLmxzWzE2NzoxNzddLCBtYy5jb3JlcyA9IDQsIGZ1bmN0aW9uKHgpewogIHgyIDwtIHggJT4lIAogICAgZmlsdGVyKHZhcmlhYmxlID09ICJJMSIgfCB2YXJpYWJsZSA9PSAiSWcxIiB8IHZhcmlhYmxlID09ICJJMiIgfCB2YXJpYWJsZSA9PSAiSWcyIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogICAgbXV0YXRlKGlkX2FsdCA9IHBhc3RlKG11dF9pZCwgcmVzX2lkKSkgJT4lIAogICAgc2VsZWN0KGlkX2FsdCwgdGltZSwgdmFyaWFibGUsIHZhbHVlKSAlPiUgCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBpZF9hbHQpKSAlPiUKICBtdXRhdGUodG90YWwxID0gSTErSWcxLCB0b3RhbDIgPSBJMitJZzIpCiAgCiAgd3JpdGVfcGFycXVldCh4MiwgcGFzdGUwKGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9pbnZhc2lvbi8iKSwgdW5pcXVlKHgyJGlkX2FsdCksICJfZGMucGFycXVldCIpKQp9KQoKIyBmZXRjaCBkYXRhCmludmFzaW9uX2R5bi5sczIgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2ludmFzaW9uIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCmludmFzaW9uX2R5bi5sczIgPC0gbGFwcGx5KGludmFzaW9uX2R5bi5sczIsIHJlYWRfcGFycXVldCkKaW52YXNpb25fZGMuZGYgPC0gZG8uY2FsbChyYmluZCwgaW52YXNpb25fZHluLmxzMikKaW52YXNpb25fZGMuZGYgPC0gaW52YXNpb25fZGMuZGYgJT4lIAogIG11dGF0ZShtdXRfaWQgPSBnc3ViKCIgLioiLCAiIiwgaWRfYWx0KSwKICAgICAgICAgcmVzX2lkID0gZ3N1YigiLiogIiwgIiIsIGlkX2FsdCkpICU+JSAKICBmaWx0ZXIobXV0X2lkICE9IHJlc19pZCkKI3dyaXRlX3BhcnF1ZXQoaW52YXNpb25fZGMuZGYsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9pbnZhc2lvbl9kYy5wYXJxdWV0IikpCmBgYAoKIyBmdXJ0aGVyIHByb2Nlc3NpbmcKYGBge3J9CmludmFzaW9uX2RjLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvaW52YXNpb25fZGMucGFycXVldCIpKQojIGdldCB3aW5uZXJzIGFuZCBsb3NlcnMKaW52YXNpb25fZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQppbnZhc2lvbl9kYy5kZjIgPC0gaW52YXNpb25fZGMuZGYgJT4lIAogIGxlZnRfam9pbihpbnZhc2lvbl9maXRuZXNzLmRmLCBieSA9IGMoIm11dF9pZCIsICJyZXNfaWQiKSkgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzPiAwIH4gdG90YWwxLAogICAgZml0bmVzczwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3MgPCAwIH4gdG90YWwxCiAgKSkgJT4lIAogIGZpbHRlcihhYnMoZml0bmVzcykgPiAwLjUpCmBgYAoKIyBwbG90CmBgYHtyfQppbnZhc2lvbl9kYy5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBpbnZhc2lvbl9kYy5kZjIsIGFlcyh4PSB0b3RhbF93aW5uZXIsIHkgPSBSLCBncm91cCA9IGlkX2FsdCwgY29sb3IgPSAiV2lubmVyIiksIGFscGhhID0gMC41LCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBnZW9tX3BhdGgoZGF0YSA9IGludmFzaW9uX2RjLmRmMiwgYWVzKHg9IHRvdGFsX2xvc2VyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIkxvc2VyIiksCiAgICAgICAgICBhbHBoYSA9IDAuNSxhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIlN0YXR1cyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIiwgeSA9ICJSQkMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJXaW5uZXIiID0gIiM0NTc1YjQiLCJMb3NlciI9ICIjZmM4ZDU5IikpICArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgJT4lIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoKIy0tLS0tLS0tLSBxdWFudGlmeWluZyBkaXNlYXNlIGN1cnZlIGFyZWEgLS0tLS0tLS0tLS0tIwojIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBhcmVhIGJldHdlZW4gc2V0cyBvZiBwb2ludHMgLT4gZnJvbSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zNjcyMjYwL2FyZWEtY292ZXJlZC1ieS1hLXBvaW50LWNsb3VkLXdpdGgtcgpgYGB7cn0KbGlicmFyeShzcGxhbmNzKQpjaGE8LWZ1bmN0aW9uKGRmKXsKICB4IDwtIGRmJHRvdGFsCiAgeSA8LSBkZiRSCmNodWxsKHgseSktPmkKcmV0dXJuKGFyZWFwbChjYmluZCh4W2ldLHlbaV0pKSkKfQpgYGAKCiMgbG9vcCB0byBnZXQgYXJlYTogc2luZ2xlIGluZmVjdGlvbgpgYGB7cn0KIyBzcGxpdCBkZgpzaV9kY19oaWdoLmxzIDwtIHNwbGl0KHNpX2RjLmhpZ2gsIHNpX2RjLmhpZ2gkZXpfbGFiZWxfc2kpCnNpX2RjX3Bvb3IubHMgPC0gc3BsaXQoc2lfZGMucG9vciwgc2lfZGMucG9vciRpZCkKCiMgZ2V0IGFyZWEKc2lfZGNfaGlnaC5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHNpX2RjX2hpZ2gubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoc2lfZGNfaGlnaC5scywgY2hhKSkpCnNpX2RjX3Bvb3IuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzaV9kY19wb29yLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KHNpX2RjX3Bvb3IubHMsIGNoYSkpKQoKCiMgam9pbiB3aXRoIGZpdG5lc3MKc2lfZml0bmVzcy5kZiA8LSBzaV9maXRuZXNzLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCgpzaV9kY19oaWdoLmFyZWEyIDwtIHNpX2RjX2hpZ2guYXJlYSAlPiUgCiAgbGVmdF9qb2luKHNpX2ZpdG5lc3MuZGYsIGJ5ID0gYygiaWRfYWx0IiA9ICJlel9sYWJlbF9zaSIpKSAlPiUgCiAgc2VsZWN0KHZhbHVlLCBhcmVhKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJTaW5nbGUgaW5mZWN0aW9uIikKCnNpX2RjX3Bvb3IuYXJlYTIgPC0gc2lfZGNfcG9vci5hcmVhICU+JSAKICBsZWZ0X2pvaW4oc2lfZml0bmVzcy5kZiwgYnkgPSBjKCJpZF9hbHQiID0gImlkIikpICU+JSAKICBzZWxlY3QodmFsdWUsIGFyZWEpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIlNpbmdsZSBpbmZlY3Rpb24iKQpgYGAKCiMgY29pbmZlY3Rpb24KYGBge3J9CiMgc3BsaXQKY2lfZGNfaGlnaC5scyA8LSBzcGxpdChjaV9kYy5oaWdoMiwgY2lfZGMuaGlnaDIkZXpfbGFiZWwpCmNpX2RjX3Bvb3IubHMgPC0gc3BsaXQoY2lfZGMucG9vciwgY2lfZGMucG9vciRsYWJlbCkKCiMgcnVuIGZ1bmN0aW9uIHRvIGZpbmQgYXJlYQpjaV9kY19oaWdoLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoY2lfZGNfaGlnaC5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShjaV9kY19oaWdoLmxzLCBjaGEpKSwgdmFsdWUgPSB1bmlxdWUoY2lfZGMuaGlnaDIkdmFsdWUpKQoKY2lfZGNfcG9vci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGNpX2RjX3Bvb3IubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoY2lfZGNfcG9vci5scywgY2hhKSksIHZhbHVlID0gdW5pcXVlKGNpX2RjLnBvb3IkdmFsdWUpKQoKIyBlZGl0IGFuZCBqb2luCmNpX2RjX2hpZ2guYXJlYTIgPC0gIGNpX2RjX2hpZ2guYXJlYSAlPiUgCiAgc2VsZWN0KGFyZWEsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJDby1pbmZlY3Rpb24iKQoKY2lfZGNfcG9vci5hcmVhMiA8LSAgY2lfZGNfcG9vci5hcmVhICU+JSAKICBzZWxlY3QoYXJlYSwgdmFsdWUpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIkNvLWluZmVjdGlvbiIpCmBgYAoKIyBkdWFsIGN1ZQpgYGB7cn0KIyBzcGxpdApkdWFsLmRjIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kYy5wYXJxdWV0IikpCmR1YWxfZGMubHMgPC0gc3BsaXQoZHVhbC5kYywgZHVhbC5kYyRsYWJlbF9hbHQpCgojIGdldCBhcmVhCmR1YWxfZGMuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShkdWFsX2RjLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KGR1YWxfZGMubHMsIGNoYSkpKQoKIyBiaW5kIHdpdGggZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSBtdXRhdGUoaWRfYWx0ID0gcGFzdGUobGFiZWwsICIrIiwgbGFiZWxfYikpCmR1YWxfZGMuYXJlYTIgPC0gZHVhbF9kYy5hcmVhICU+JSAKICBsZWZ0X2pvaW4oZHVhbF9maXRuZXNzLmRmLCBieSA9ICJpZF9hbHQiKSAlPiUgCiAgc2VsZWN0KGFyZWEsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJEdWFsLWN1ZSIpICU+JSAKICBmaWx0ZXIodmFsdWUgPiAyKQpkdWFsX2RjLmFyZWEyCmBgYAoKIy0tLS0tLSBnZXQgZml0dGVkIHNjYXR0ZXIgcGxvdCBmb3IgYWxsIHNpbmdsZSBpbmZlY3Rpb24sIGNvIGluZmVjdGlvbiwgYW5kIGR1YWwgY3VlIC0tLS0tLS0tIwpgYGB7cn0KIyByYmluZApzaS5hcmVhIDwtIHJiaW5kKHNpX2RjX2hpZ2guYXJlYTIsIHNpX2RjX3Bvb3IuYXJlYTIpCmNpLmFyZWEgPC0gcmJpbmQoY2lfZGNfaGlnaC5hcmVhMiwgY2lfZGNfcG9vci5hcmVhMikKZHVhbC5hcmVhIDwtIGR1YWxfZGMuYXJlYTIKCiMgcGxvdApsaWJyYXJ5KCJnZ3BtaXNjIikKCnNpX2FyZWEucGwgPC0gZ2dwbG90KGRhdGEgPSBzaS5hcmVhLCBhZXMoeCA9IGFyZWEsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfcG9seV9saW5lKGNvbG9yID0gImJsYWNrIikgKwogIHN0YXRfcG9seV9lcSgpICsKICBsYWJzKHggPSAiQXJlYSIsIHkgPSAiRml0bmVzcyIsIGNvbG9yID0gIlN0YXR1cyIpICsKICB0aGVtZV9idygpCgpjaV9hcmVhLnBsIDwtIGdncGxvdChkYXRhID0gY2kuYXJlYSwgYWVzKHggPSBhcmVhLCB5ID0gdmFsdWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3BvbHlfbGluZShjb2xvciA9ICJibGFjayIpICsKICBzdGF0X3BvbHlfZXEoKSArCiAgbGFicyh4ID0gIkFyZWEiLCB5ID0gIkZpdG5lc3MiLCBjb2xvciA9ICJTdGF0dXMiKSArCiAgdGhlbWVfYncoKQoKZHVhbF9hcmVhLnBsIDwtIGdncGxvdChkYXRhID0gZHVhbC5hcmVhLCBhZXMoeCA9IGFyZWEsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfcG9seV9saW5lKGNvbG9yPSAiYmxhY2siKSArCiAgc3RhdF9wb2x5X2VxKCkgKwogIGxhYnMoeCA9ICJBcmVhIiwgeSA9ICJGaXRuZXNzIiwgY29sb3IgPSAiU3RhdHVzIikgKwogIHRoZW1lX2J3KCkKYGBgCgoKIy0tLS0tLS0gcGxvdCB0b2dldGhlciB3aXRoIGRpc2Vhc2UgY3VydmUgLS0tLS0tLS0jCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24Kc2lfdmlyLnBsIDwtIGdnYXJyYW5nZShzaV9kYy5wbCwgc2lfYXJlYS5wbCwgYWxpZ24gPSAidiIsIHdpZHRocyA9IGMoMSwgMC40NSkpCgojIGNvLWluZmVjdGlvbgpjaV92aXIucGwgPC0gZ2dhcnJhbmdlKGNpX2RjLnBsLCBjaV9hcmVhLnBsLCBhbGlnbiA9ICJ2Iiwgd2lkdGhzID0gYygxLCAwLjQ1KSkKCiMgZHVhbC1jdWUKZHVhbF92aXIucGwgPC0gZ2dhcnJhbmdlKGR1YWxfZGMucGwsIGR1YWxfYXJlYS5wbCwgYWxpZ24gPSAidiIsIHdpZHRocyA9IGMoMSwgMC40NSkpCmBgYAoKCiMtLS0tLS0tLS0gc3RhdGljIGFyZWEgY29tcGFyaXNvbiAtLS0tLS0tLS0tLS0tIwojIGNvbXB1dGUgYXJlYQpgYGB7cn0KIyBpbXBvcnQgaW4gZGMgZHluYW1pYyBhbmQgZml0bmVzcwpzdGF0aWNfZGMuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zdGF0aWNfZGMucGFycXVldCIpKQpzdGF0aWNfZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKCiMgZ2V0IHdpbm5lciBhbmQgbG9zZXIKc3RhdGljX2RjLmRmNCA8LSBzdGF0aWNfZGMuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc3RhdGljX2ZpdG5lc3MuZGYsIGlkXzEsIGlkXzIsIGZpdG5lc3NfZGlmZmVyZW5jZSksIGJ5ID0gYygiaWRfMSIsICJpZF8yIikpICU+JQogIGZpbHRlcihpZF8xICE9IGlkXzIpICU+JSAKICBtdXRhdGUoCiAgdG90YWxfd2lubmVyID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMSwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwyLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwxCiAgKSklPiUgCiAgZmlsdGVyKGFicyhmaXRuZXNzX2RpZmZlcmVuY2UpID4gMC41KQoKIyBzcGxpdCBieSB3aW5uZXIgYW5kIGxvc2VyCnN0YXRpY19kYy5sczEgPC0gc3BsaXQoc2VsZWN0KHN0YXRpY19kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfd2lubmVyKSwgc3RhdGljX2RjLmRmNCRpZF9hbHQpCnN0YXRpY19kYy5sczIgPC0gc3BsaXQoc2VsZWN0KHN0YXRpY19kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfbG9zZXIpLCBzdGF0aWNfZGMuZGY0JGlkX2FsdCkKCiMgZ2V0IGFyZWEKc3RhdGljX3dpbi5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHN0YXRpY19kYy5sczEsIGNoYSkpLCBzdGF0dXMgPSAiV2lubmVyIikKc3RhdGljX2xvc2VyLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc3RhdGljX2RjLmxzMiwgY2hhKSksIHN0YXR1cyA9ICJMb3NlciIpCgojIHBhaXIKc3RhdGljLmFyZWEgPC0gY2JpbmQoc2VsZWN0KHN0YXRpY193aW4uYXJlYSwgV2lubmVyID0gYXJlYSksCiAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChzdGF0aWNfbG9zZXIuYXJlYSwgTG9zZXIgPSBhcmVhKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShXaW5uZXI+TG9zZXIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiLCAiTG9zZXIgbGFyZ2VyIGFyZWEiKSkKYGBgCgojIHBsb3Qgc3RhdGljCmBgYHtyfQpzdGF0aWNfYXJlYS5wbCA8LSBnZ3BhaXJlZChzdGF0aWMuYXJlYSwgY29uZDEgPSAiV2lubmVyIiwgY29uZDIgPSAiTG9zZXIiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiU3RhdHVzIiwgeSA9ICJBcmVhIiwgY29sb3IgPSAiQ29tcGFyaXNvblxuKFN0YXRpYykiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkxvc2VyIGxhcmdlciBhcmVhIiA9ICIjZmM4ZDU5IiwgIldpbm5lciBsYXJnZXIgYXJlYSIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gMCkgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQpgYGAKCgojLS0tLS0tLS0tIGludmFzaW9uIGFyZWEgY29tcGFyaXNvbiAtLS0tLS0tLS0tLS0tLS0tLSMKIyBnZXQgYXJlYQpgYGB7cn0KIyBpbXBvcnQgaW4gZGMgZHluYW1pYyBhbmQgZml0bmVzcwppbnZhc2lvbl9kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2ludmFzaW9uX2RjLnBhcnF1ZXQiKSkKaW52YXNpb25fZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQoKaW52YXNpb25fZGMuZGY0IDwtIGludmFzaW9uX2RjLmRmICU+JSAKICBsZWZ0X2pvaW4oaW52YXNpb25fZml0bmVzcy5kZiwgYnkgPSBjKCJtdXRfaWQiLCAicmVzX2lkIikpICU+JSAKICBtdXRhdGUoCiAgdG90YWxfd2lubmVyID0gY2FzZV93aGVuKAogICAgZml0bmVzcz4gMCB+IHRvdGFsMSwKICAgIGZpdG5lc3M8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzcyA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzIDwgMCB+IHRvdGFsMQogICkpICU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3MpID4gMC41KQoKIyBzcGxpdCBieSB3aW5uZXIgYW5kIGxvc2VyCmludmFzaW9uX2RjLmxzMSA8LSBzcGxpdChzZWxlY3QoaW52YXNpb25fZGMuZGY0LCBSLCB0b3RhbCA9IHRvdGFsX3dpbm5lciksIGludmFzaW9uX2RjLmRmNCRpZF9hbHQpCmludmFzaW9uX2RjLmxzMiA8LSBzcGxpdChzZWxlY3QoaW52YXNpb25fZGMuZGY0LCBSLCB0b3RhbCA9IHRvdGFsX2xvc2VyKSwgaW52YXNpb25fZGMuZGY0JGlkX2FsdCkKCiMgZ2V0IGFyZWEKaW52YXNpb25fd2luLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoaW52YXNpb25fZGMubHMxLCBjaGEpKSwgc3RhdHVzID0gIldpbm5lciIpCmludmFzaW9uX2xvc2VyLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoaW52YXNpb25fZGMubHMyLCBjaGEpKSwgc3RhdHVzID0gIkxvc2VyIikKCiMgcGFpcgppbnZhc2lvbi5hcmVhIDwtIGNiaW5kKHNlbGVjdChpbnZhc2lvbl93aW4uYXJlYSwgV2lubmVyID0gYXJlYSksCiAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChpbnZhc2lvbl9sb3Nlci5hcmVhLCBMb3NlciA9IGFyZWEpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFdpbm5lcj5Mb3NlciwgIldpbm5lciBsYXJnZXIgYXJlYSIsICJMb3NlciBsYXJnZXIgYXJlYSIpKQpgYGAKCiMgcGxvdApgYGB7cn0KaW52YXNpb25fYXJlYS5wbCA8LWdncGFpcmVkKGludmFzaW9uLmFyZWEsIGNvbmQxID0gIldpbm5lciIsIGNvbmQyID0gIkxvc2VyIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC4yKSArCiAgbGFicyh4ID0gIlN0YXR1cyIsIHkgPSAiQXJlYSIsIGNvbG9yID0gIkNvbXBhcmlzb25cbihJbnZhc2l2ZSkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkxvc2VyIGxhcmdlciBhcmVhIiA9ICIjZmM4ZDU5IiwgIldpbm5lciBsYXJnZXIgYXJlYSIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gMCkgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQogIApgYGAKCiMtLS0tLS0gcGxvdCB0b2dldGhlciAtLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBwYWlyd2lzZSBjb21wYXJpc29uIGZvciBzdGF0aWMgYW5kIGludmFzaXZlIGNvbWVwdGl0aW9uCmhldGVyb2N1ZV9jb21wLnBsIDwtIGdnYXJyYW5nZShzdGF0aWNfYXJlYS5wbCwgaW52YXNpb25fYXJlYS5wbCwgbmNvbCA9IDIsIG5yb3cgPSAxLCBhbGlnbiA9ICJ2IikKCiMgam9pbiBpbnRoZSBvdGhlciBkaXNlYXNlIGN1cnZlcwpnZ2FycmFuZ2Uoc2lfdmlyLnBsLCBjaV92aXIucGwsIGR1YWxfdmlyLnBsLCBoZXRlcm9jdWVfY29tcC5wbCwgbmNvbCA9IDIsIG5yb3cgPSAyLCBsYWJlbHMgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiksIGhlaWdodHMgPSBjKDEsIDAuOCkpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby92aXJ1bGVuY2UudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTYwMCwgc2NhbGUgPSAyLCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZHVhbCBjdWUgZHluYW1pY3MgZmlndXJlCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKCiMgZ2V0IGR1YWwgZHluYW1pY3MKYGBge3J9CmR1YWwuZHluIDwtIGNoYWJhdWRpX3NpX2NsZWFuKAogIHBhcmFtZXRlcnNfY3IgPSBjKDQuNDQ2MTkyMDMzLAkxMC45NzUxODI3NSwJMS4zODc2MjgxNywJMjMuMzA1OTI1NCwJLTMuNDUyMDUyMzcxLAktMTguMDA3MDY5MiwJMzkuNjY2MTQyMjYsCS0zLjU0NTE5MzE0MSwJMTguNzgzNTA3OTkpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDMwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoNiwgNywgYnkgPSAxLzUwMCksCiAgY3VlX3JhbmdlX2IgPSBzZXEoMCwgbG9nMTAoNiooMTBeNikpLCBieSA9IChsb2cxMCg2KigxMF42KSkpLzUwMCksCiAgY3VlID0gIlIiLAogIGN1ZV9iID0gIkkiLAogIGxvZ19jdWUgPSAibG9nMTAiLAogIGxvZ19jdWVfYiA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQKKQoKIyBmaWx0ZXIgb3V0IHJlbGV2ZW50IGRhdGFmcmFtZXMKZHVhbC5keW5fZiA8LSBkdWFsLmR5biAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlICVpbiUgYygiSSIsICJJZyIsICJHIiwgIlIiLCAiTiIsICJXIikpCgojIGNyIG9ubHkKZHVhbC5keW5fY3IgPC0gZHVhbC5keW4gJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKQpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9JLnBsdCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkkiKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjUpKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIkkiICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjUpKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LioxMF41LCBuYW1lPSJBc2V4dWFsIGlSQkMgcGVyIMK1TCIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX0lnLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSWciKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjUpKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIklnIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNSwgbmFtZT0iU2V4dWFsIGlSQkMgcGVyIMK1TCIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX0cucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJHIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF40KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJHIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF40KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNCwgbmFtZT0iR2FtZXRvY3l0ZSBwZXIgwrVMIikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfUi5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIlIiKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjcpKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIlIiICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUvKDEwXjcpKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LioxMF43LCBuYW1lPSJSQkMgcGVyIMK1TCIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX04ucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJOIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjEwKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIk4iICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUqMTApLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjAuMSwgbmFtZT0iSW5kaXNjcmltaW5hdGUgaW1tdW5pdHkiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9XLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiVyIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSoyKSwKICAgICAgICAgICAgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIlciICYgcm93X251bWJlcigpICUlIDEwMDAgPT0gMCksIAogICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUqMiksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMC41LCBuYW1lPSJUYXJnZXRlZCBpbW11bml0eSIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQpnZ2FycmFuZ2UoZHVhbF9JLnBsdCwgZHVhbF9JZy5wbHQsIGR1YWxfRy5wbHQsIGR1YWxfUi5wbHQsIGR1YWxfTi5wbHQsIGR1YWxfVy5wbHQsIG5yb3cgPSAzLCBuY29sID0gMiwgYWxpZ24gPSAiaHYiLCBsYWJlbHMgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkUiLCAiRiIpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2R5bi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAyMDAwLCBzY2FsZSA9IDEsIGRwaT0zMDAsIGJnID0gIndoaXRlIikKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgU2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gdmVyaWZpY2F0aW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBzaW5nbGUgaW5mZWN0aW9uCmBgYHtyfQojIGltcG9ydCBpbiBhbGwgc2luZ2xlIGluZmVjdGlvbiBkYXRhCnNpX3ZhbC5scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL3NpX3ZhbGlkYXRpb24iKSwgcGF0dGVybiA9ICIqLmNzdiIsIGZ1bGwubmFtZXMgPSBUKQoKc2lfdmFsLmRmIDwtIGxhcHBseShzaV92YWwubHMsIHJlYWQuY3N2KQpzaV92YWwuZGYgPC0gZG8uY2FsbChyYmluZCwgc2lfdmFsLmRmKQoKIyBnZXQgbWF4IGZpdG5lc3MgZnJvbSBzaW11bGF0aW9uLiBsZWZ0IGpvaW4gd2l0aCBzaV9vcHQKc2lfb3B0LmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvc2lfb3B0LmNzdiIpKQoKIyB3ZSBjYW4gc2VlIHRoYXQgYWxsIG9mIHRoZSByYW5kb21seSBzaW11bGF0ZWQgbW9kZWxzIGhhdmUgYSBmaXRuZXNzIHZhbHVlIHRoYXQgaXMgbGVzcyB0aGFuIHRoZSBvcHRpbWl6ZWQgbW9kZWwKc2lfdmFsLmRmMiA8LSBzZWxlY3Qoc2lfdmFsLmRmLCBWMSwgaWQpICU+JQogIGxlZnRfam9pbihzaV9vcHQuZGYsIGJ5ID1jKCJpZCIgPSAiaWQiKSkgJT4lIAogIG11dGF0ZShmaXRuZXNzX2RpZmZlcmVuY2UgPSBmaXRuZXNzXzIwIC0gVjEpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9zaSwgZXpfbGFiZWxfc2kpLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQpgYGAKCiMjIyBNb2RlbCB2YWxpZGF0aW9uCmBgYHtyfQojIHJlYWQgaW4gdGhlIHJlc3VsdHMgZmlsZQpjaV92YWwubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV92YWxpZGF0aW9uIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKY2lfdmFsLmxzMiA8LSBsYXBwbHkoY2lfdmFsLmxzLCByZWFkLmNzdikKY2lfdmFsLmRmIDwtIGRvLmNhbGwocmJpbmQsIGNpX3ZhbC5sczIpCgpjaV92YWwuZGYyCmNpX3ZhbC5kZjIgPC0gY2lfdmFsLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9jaSwgZXpfbGFiZWwpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9jaSIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc2lfdmFsLnBsdCA8LSBnZ3Bsb3QoZGF0YSA9IHNpX3ZhbC5kZjIsIGFlcyh4ID0gZml0bmVzc19kaWZmZXJlbmNlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gIiNmYzhkNTkiKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWxfc2ksIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDMpICsKICBsYWJzKHggPSAiT3B0aW1pemVkIGZpdG5lc3MgLSByYW5kb20gZml0bmVzcyIsIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX2J3KCkKCmNpX3ZhbC5wbHQgPC0gZ2dwbG90KGRhdGEgPSBjaV92YWwuZGYyLCBhZXMoeCA9IFYxKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gIiNmYzhkNTkiKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWwsIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDQpICsKICBsYWJzKHggPSAiRml0bmVzcyBkaWZmZXJlbmNlIGJldHdlZW5cbm9wdGltaXplZCBhbmQgcmFuZG9tIHN0cmFpbiIsIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX2J3KCkKCmdnYXJyYW5nZShzaV92YWwucGx0LCBjaV92YWwucGx0LCBhbGlnbiA9ICJodiIsIGxhYmVscyA9IGMoIkEiLCAiQiIpLCB3aWR0aHMgPSBjKDMsNCkpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3ZhbGlkYXRpb24udGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTMwMCwgc2NhbGUgPSAxLjYsIGRwaT0zMDAsIGJnID0gIndoaXRlIikKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBNb250ZSBjYXJsbyBkeW5hbWljcyBzdXBwbGVtZW50YXJ5CiM9PT09PT09PT09PT09PT09PT09PT09PT09IwojIHJ1biBjb2RlIGluIHJlcG9ydCAxNgpgYGB7cn0KbWNfZHluX2EgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gcmVmZXJlbmNlLmRmLCBhZXMoeCA9IHRpbWUsIHkgPSBjcikpICsKICBnZW9tX3JpYmJvbihkYXRhID0gZGlmZi5kZiwgYWVzKHggPSB0aW1lLCB5bWluID0gY3JfYm90LCB5bWF4ID0gY3JfdG9wKSwgYWxwaGEgPSAwLjUsIGZpbGwgPSAiI2ZjOGQ1OSIpICsKICBmYWNldF93cmFwKH5jdWUsIG5jb2wgPSAyKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfYncoKQogIAojIHBsb3QgZml0bmVzcyB0aW1lc2VyaWVzLiBXaGVuIGlmIHRpbmVzcyBsb3N0PyBBdCB0aGUgbGF0dGVyIHBhcnQKbWNfZHluX2IgIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IHJlZmVyZW5jZS5kZiwgYWVzKHggPSB0aW1lLCB5ID0gdGF1KSkgKwogIGdlb21fcmliYm9uKGRhdGEgPSBkaWZmLmRmLCBhZXMoeCA9IHRpbWUsIHltaW4gPSB0YXVfYm90LCB5bWF4ID0gdGF1X3RvcCksIGFscGhhID0gMC41LCBmaWxsID0gIiNmYzhkNTkiKSArCiAgZmFjZXRfd3JhcCh+Y3VlLCBuY29sID0gMikgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiVHJhbnNtaXNzaW9uIHBvdGVudGlhbCIpICsKICB0aGVtZV9idygpCgpnZ2FycmFuZ2UobWNfZHluX2EsIG1jX2R5bl9iLCBuY29sID0gMSwgYWxpZ24gPSAidiIsIGxhYmVscyA9IGMoIkEiLCAiQiIpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9NQ19keW4udGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjAwMCwgaGVpZ2h0ID0gMjYwMCwgc2NhbGUgPSAxLCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKCgo=